<commit_before>#[macro_use] extern crate conrod;
extern crate find_folder;
extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use conrod::{
    Background,
    Color,
    Colorable,
    Label,
    Labelable,
    Positionable,
    Theme,
    Toggle,
    Ui,
    Widget
};
use conrod::color::{black, green, red};
use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use opengl_graphics::glyph_cache::GlyphCache;
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;
type RcGraphics = Rc<RefCell<GlGraphics>>;
type RcUi = Rc<RefCell<Ui<GlyphCache<'static>>>>;

struct App {
    window: RcWindow,
    graphics: RcGraphics,
    ui: RcUi,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor: VirtualCursor,
    bg_color: Color
}

widget_ids! {
    TITLE
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor.position = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {
        // we need to pass the window to update (and set the size here) because using
        // the update event from the window events queue is currently broken.
        self.translator.set_size(self.window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();
        let mut ui = &mut *self.ui.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color.to_fsa(), gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color.to_fsa(),
                                                                square,
                                                                c.transform,
                                                                gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor.position[0],
                                      self.cursor.position[1],
                                      self.cursor.size);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(self.cursor.color.to_fsa(),
                                                              dot,
                                                              c.transform,
                                                              gl));
        }

        // draw the ui
        {
            Background::new().color(self.bg_color).set(ui);

            Label::new("Hello")
                .xy(-150.0, -150.0)
                .font_size(32)
                .color(self.bg_color.plain_contrast())
                .set(TITLE, ui);
        }
    }
}

struct Character {
    color: Color,
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: Color, tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

struct VirtualCursor {
    position: [f64; 2],
    color: Color,
    size: f64
}

impl VirtualCursor {
    fn new() -> Self {
        VirtualCursor {
            position: [0.0, 0.0],
            color: green(),
            size: 5.0
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .ok()
        .expect("Could not create main window");

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .y_motion_inverted(true)
        .build_translator();

    let character = {
        const INITIAL_CHARACTER_POS: [f64; 2] = [WINDOW_SIZE.0 as f64 / 20.0,
                                                 WINDOW_SIZE.1 as f64 * 0.85];
        Character::new(red(), INITIAL_CHARACTER_POS, 50.0)
    };

    let ui = {
        let glyph_cache = {
            let font_path = find_folder::Search::ParentsThenKids(3, 3)
                .for_folder("assets")
                .ok()
                .expect("Could not find assets folder")
                .join("fonts/NotoSans/NotoSans-Regular.ttf");

            GlyphCache::new(&font_path)
                .ok()
                .expect("Could not find font file within assets folder")
        };

        Ui::new(glyph_cache, Theme::default())
    };

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        ui: Rc::new(RefCell::new(ui)),
        translator: translator,
        character: character,
        cursor: VirtualCursor::new(),
        bg_color: black()
    };

    for e in app.window.clone().events() {
        match e {
            Event::Input(i) => { app.input(&i); },
            Event::Update(u) => { app.update(&u); },
            Event::Render(r) => { app.render(&r); },
            _ => { }
        }
    }
}<commit_msg>Got the text drawing<commit_after>#[macro_use] extern crate conrod;
extern crate find_folder;
extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use conrod::{
    Background,
    Color,
    Colorable,
    Label,
    Labelable,
    Positionable,
    Theme,
    Toggle,
    Ui,
    Widget
};
use conrod::color::{black, green, red};
use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use opengl_graphics::glyph_cache::GlyphCache;
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;
type RcGraphics = Rc<RefCell<GlGraphics>>;
type RcUi = Rc<RefCell<Ui<GlyphCache<'static>>>>;

struct App {
    window: RcWindow,
    graphics: RcGraphics,
    ui: RcUi,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor: VirtualCursor,
    bg_color: Color
}

widget_ids! {
    TITLE
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor.position = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {
        // we need to pass the window to update (and set the size here) because using
        // the update event from the window events queue is currently broken.
        self.translator.set_size(self.window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();
        let ui = &mut *self.ui.borrow_mut();

        // draw the ui
        gl_graphics.draw(args.viewport(), |c, gl| {
            Background::new().color(self.bg_color).set(ui);

            Label::new("Hello")
                .xy(10.0, 10.0)
                .font_size(32)
                .color(self.bg_color.plain_contrast())
                .set(TITLE, ui);

            ui.draw(c, gl)
        });

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color.to_fsa(),
                                                                square,
                                                                c.transform,
                                                                gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor.position[0],
                                      self.cursor.position[1],
                                      self.cursor.size);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(self.cursor.color.to_fsa(),
                                                              dot,
                                                              c.transform,
                                                              gl));
        }
    }
}

struct Character {
    color: Color,
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: Color, tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

struct VirtualCursor {
    position: [f64; 2],
    color: Color,
    size: f64
}

impl VirtualCursor {
    fn new() -> Self {
        VirtualCursor {
            position: [0.0, 0.0],
            color: green(),
            size: 5.0
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .ok()
        .expect("Could not create main window");

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .y_motion_inverted(true)
        .build_translator();

    let character = {
        const INITIAL_CHARACTER_POS: [f64; 2] = [WINDOW_SIZE.0 as f64 / 20.0,
                                                 WINDOW_SIZE.1 as f64 * 0.85];
        Character::new(red(), INITIAL_CHARACTER_POS, 50.0)
    };

    let ui = {
        let glyph_cache = {
            let font_path = find_folder::Search::ParentsThenKids(3, 3)
                .for_folder("assets")
                .ok()
                .expect("Could not find assets folder")
                .join("fonts/NotoSans/NotoSans-Regular.ttf");

            GlyphCache::new(&font_path)
                .ok()
                .expect("Could not find font file within assets folder")
        };

        Ui::new(glyph_cache, Theme::default())
    };

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        ui: Rc::new(RefCell::new(ui)),
        translator: translator,
        character: character,
        cursor: VirtualCursor::new(),
        bg_color: black()
    };

    for e in app.window.clone().events() {
        match e {
            Event::Input(i) => { app.input(&i); },
            Event::Update(u) => { app.update(&u); },
            Event::Render(r) => { app.render(&r); },
            _ => { }
        }
    }
}<|endoftext|>


<commit_before>#![allow(unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;

struct App {
    window: RcWindow,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    virtual_cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0f64;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.virtual_cursor_pos = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs, window: RcWindow) {
        // we need to pass the window to update (and set the size here) because using
        // the update event from the window events queue is currently broken.
        self.translator.set_size(window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color, square, c.transform, gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.virtual_cursor_pos[0], self.virtual_cursor_pos[1], 5.0);
            const CURSOR_DOT_COLOR: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(CURSOR_DOT_COLOR, dot, c.transform, gl));
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, (WINDOW_SIZE.1 as f64) * 0.85],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        virtual_cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in  app.window.clone().events() {
        let app_window = app.window.clone();
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u, app_window); },
            Event::Input(i) => { app.input(&i); },
            _ => { }
        }
    }
}
<commit_msg>Create a struct to hold virtual cursor information<commit_after>#![allow(unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;

struct App {
    window: RcWindow,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor: VirtualCursor,
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0f64;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor.position = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs, window: RcWindow) {
        // we need to pass the window to update (and set the size here) because using
        // the update event from the window events queue is currently broken.
        self.translator.set_size(window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color, square, c.transform, gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor.position[0],
                                      self.cursor.position[1],
                                      self.cursor.size);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(self.cursor.color, dot, c.transform, gl));
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

struct VirtualCursor {
    position: [f64; 2],
    color: [f32; 4],
    size: f64
}

impl VirtualCursor {
    fn new() -> Self {
        VirtualCursor {
            position: [0.0, 0.0],
            color: [0.0, 1.0, 0.0, 1.0],
            size: 5.0
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, (WINDOW_SIZE.1 as f64) * 0.85],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        cursor: VirtualCursor::new(),
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in  app.window.clone().events() {
        let app_window = app.window.clone();
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u, app_window); },
            Event::Input(i) => { app.input(&i); },
            _ => { }
        }
    }
}
<|endoftext|>


<commit_before>use bullet;
use bullet::bullets::Bullets;
use bullet::collision::CollisionSystem;
use cgmath;
use character;
use character::controls::CharacterControlSystem;
use critter::CharacterSprite;
use gfx_app::{Window, GameStatus};
use gfx_app::renderer::{DeviceRenderer, EncoderQueue};
use gfx_app::system::DrawSystem;
use gfx;
use gfx_app::controls::TilemapControls;
use gfx_app::mouse_controls::{MouseControlSystem, MouseInputState};
use graphics;
use graphics::{Dimensions, DeltaTime};
use graphics::camera::CameraControlSystem;
use house;
use terrain;
use std::time;
use std::sync::mpsc;
use specs;
use specs::World;
use specs::DispatcherBuilder;
use zombie;
use zombie::zombies::Zombies;

pub fn run<W, D, F>(window: &mut W) -> GameStatus
                    where W: Window<D, F>,
                          D: gfx::Device + 'static,
                          F: gfx::Factory<D::Resources>,
                          D::CommandBuffer: Send {
  let (mut device_renderer, enc_queue) = DeviceRenderer::new(window.create_buffers(2));

  let mut w = specs::World::new();
  setup_world(&mut w, window.get_viewport_size());
  dispatch_loop(window, &mut device_renderer, &mut w, enc_queue)
}

fn setup_world(world: &mut World, viewport_size: (u32, u32)) {
  world.register::<terrain::TerrainDrawable>();
  world.register::<graphics::camera::CameraInputState>();
  world.register::<character::CharacterDrawable>();
  world.register::<house::HouseDrawable>();
  world.register::<Zombies>();
  world.register::<Bullets>();
  world.register::<CharacterSprite>();
  world.register::<character::controls::CharacterInputState>();
  world.register::<MouseInputState>();

  world.add_resource(terrain::tilemap::generate());
  world.add_resource(Dimensions::new(viewport_size.0, viewport_size.1));
  world.add_resource(graphics::camera::CameraInputState::new());
  world.add_resource(character::controls::CharacterInputState::new());
  world.add_resource(MouseInputState::new());
  world.add_resource(DeltaTime(0.0));

  world.create_entity()
       .with(terrain::TerrainDrawable::new())
       .with(character::CharacterDrawable::new())
       .with(house::HouseDrawable::new(cgmath::Point2::new(0.0, 750.0)))
       .with(Zombies::new())
       .with(Bullets::new())
       .with(CharacterSprite::new())
       .with(graphics::camera::CameraInputState::new())
       .with(character::controls::CharacterInputState::new())
       .with(MouseInputState::new()).build();
}

fn dispatch_loop<W, D, F>(window: &mut W,
                          device_renderer: &mut DeviceRenderer<D>,
                          w: &mut World,
                          encoder_queue: EncoderQueue<D>) -> GameStatus
                          where W: Window<D, F>,
                                D: gfx::Device + 'static,
                                F: gfx::Factory<D::Resources>,
                                D::CommandBuffer: Send {
  let draw = {
    let rtv = window.get_render_target_view();
    let dsv = window.get_depth_stencil_view();
    DrawSystem::new(window.get_factory(), &rtv, &dsv, encoder_queue)
  };

  let (_, game_state) = mpsc::channel::<GameStatus>();

  let (terrain_system, terrain_control) = CameraControlSystem::new();
  let (character_system, character_control) = CharacterControlSystem::new();
  let (mouse_system, mouse_control, ) = MouseControlSystem::new();
  let controls = TilemapControls::new(terrain_control, character_control, mouse_control);

  let mut dispatcher = DispatcherBuilder::new()
    .add(draw, "drawing", &[])
    .add(terrain::PreDrawSystem::new(), "draw-prep-terrain", &["drawing"])
    .add(character::PreDrawSystem::new(), "draw-prep-character", &["drawing"])
    .add(zombie::PreDrawSystem::new(), "draw-prep-zombie", &["drawing"])
    .add(bullet::PreDrawSystem::new(), "draw-prep-bullet", &["drawing"])
    .add(terrain_system, "terrain-system", &[])
    .add(house::PreDrawSystem::new(), "draw-prep-house", &["terrain-system"])
    .add(character_system, "character-system", &[])
    .add(mouse_system, "mouse-system", &[])
    .add(CollisionSystem::new(), "collision-system", &["mouse-system"])
    .build();

  window.set_controls(controls);

  let mut last_time = time::Instant::now();
  loop {
    let elapsed = last_time.elapsed();
    let delta = f64::from(elapsed.subsec_nanos()) / 1e9 + elapsed.as_secs() as f64;
    last_time = time::Instant::now();

    dispatcher.dispatch(&w.res);
    w.maintain();

    *w.write_resource::<DeltaTime>() = DeltaTime(delta);

    device_renderer.draw(window.get_device());
    window.swap_window();

    if let Some(quit_status) = window.poll_events() {
      return quit_status;
    }

    if let Ok(quit_status) = game_state.try_recv() {
      return quit_status;
    }
  }
}
<commit_msg>Remove obsolete resources<commit_after>use bullet;
use bullet::bullets::Bullets;
use bullet::collision::CollisionSystem;
use cgmath;
use character;
use character::controls::CharacterControlSystem;
use critter::CharacterSprite;
use gfx_app::{Window, GameStatus};
use gfx_app::renderer::{DeviceRenderer, EncoderQueue};
use gfx_app::system::DrawSystem;
use gfx;
use gfx_app::controls::TilemapControls;
use gfx_app::mouse_controls::{MouseControlSystem, MouseInputState};
use graphics;
use graphics::{Dimensions, DeltaTime};
use graphics::camera::CameraControlSystem;
use house;
use terrain;
use std::time;
use std::sync::mpsc;
use specs;
use specs::World;
use specs::DispatcherBuilder;
use zombie;
use zombie::zombies::Zombies;

pub fn run<W, D, F>(window: &mut W) -> GameStatus
                    where W: Window<D, F>,
                          D: gfx::Device + 'static,
                          F: gfx::Factory<D::Resources>,
                          D::CommandBuffer: Send {
  let (mut device_renderer, enc_queue) = DeviceRenderer::new(window.create_buffers(2));

  let mut w = specs::World::new();
  setup_world(&mut w, window.get_viewport_size());
  dispatch_loop(window, &mut device_renderer, &mut w, enc_queue)
}

fn setup_world(world: &mut World, viewport_size: (u32, u32)) {
  world.register::<terrain::TerrainDrawable>();
  world.register::<graphics::camera::CameraInputState>();
  world.register::<character::CharacterDrawable>();
  world.register::<house::HouseDrawable>();
  world.register::<Zombies>();
  world.register::<Bullets>();
  world.register::<CharacterSprite>();
  world.register::<character::controls::CharacterInputState>();
  world.register::<MouseInputState>();

  world.add_resource(Dimensions::new(viewport_size.0, viewport_size.1));
  world.add_resource(character::controls::CharacterInputState::new());
  world.add_resource(MouseInputState::new());
  world.add_resource(DeltaTime(0.0));

  world.create_entity()
       .with(terrain::TerrainDrawable::new())
       .with(character::CharacterDrawable::new())
       .with(house::HouseDrawable::new(cgmath::Point2::new(0.0, 750.0)))
       .with(Zombies::new())
       .with(Bullets::new())
       .with(CharacterSprite::new())
       .with(graphics::camera::CameraInputState::new())
       .with(character::controls::CharacterInputState::new())
       .with(MouseInputState::new()).build();
}

fn dispatch_loop<W, D, F>(window: &mut W,
                          device_renderer: &mut DeviceRenderer<D>,
                          w: &mut World,
                          encoder_queue: EncoderQueue<D>) -> GameStatus
                          where W: Window<D, F>,
                                D: gfx::Device + 'static,
                                F: gfx::Factory<D::Resources>,
                                D::CommandBuffer: Send {
  let draw = {
    let rtv = window.get_render_target_view();
    let dsv = window.get_depth_stencil_view();
    DrawSystem::new(window.get_factory(), &rtv, &dsv, encoder_queue)
  };

  let (_, game_state) = mpsc::channel::<GameStatus>();

  let (terrain_system, terrain_control) = CameraControlSystem::new();
  let (character_system, character_control) = CharacterControlSystem::new();
  let (mouse_system, mouse_control, ) = MouseControlSystem::new();
  let controls = TilemapControls::new(terrain_control, character_control, mouse_control);

  let mut dispatcher = DispatcherBuilder::new()
    .add(draw, "drawing", &[])
    .add(terrain::PreDrawSystem::new(), "draw-prep-terrain", &["drawing"])
    .add(character::PreDrawSystem::new(), "draw-prep-character", &["drawing"])
    .add(zombie::PreDrawSystem::new(), "draw-prep-zombie", &["drawing"])
    .add(bullet::PreDrawSystem::new(), "draw-prep-bullet", &["drawing"])
    .add(terrain_system, "terrain-system", &[])
    .add(house::PreDrawSystem::new(), "draw-prep-house", &["terrain-system"])
    .add(character_system, "character-system", &[])
    .add(mouse_system, "mouse-system", &[])
    .add(CollisionSystem::new(), "collision-system", &["mouse-system"])
    .build();

  window.set_controls(controls);

  let mut last_time = time::Instant::now();
  loop {
    let elapsed = last_time.elapsed();
    let delta = f64::from(elapsed.subsec_nanos()) / 1e9 + elapsed.as_secs() as f64;
    last_time = time::Instant::now();

    dispatcher.dispatch(&w.res);
    w.maintain();

    *w.write_resource::<DeltaTime>() = DeltaTime(delta);

    device_renderer.draw(window.get_device());
    window.swap_window();

    if let Some(quit_status) = window.poll_events() {
      return quit_status;
    }

    if let Ok(quit_status) = game_state.try_recv() {
      return quit_status;
    }
  }
}
<|endoftext|>


<commit_before>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient "group-and-fold" operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
///
// See [`.into_grouping_map()`](../trait.Itertools.html#method.into_grouping_map)
// for more information.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the key, the previously accumulated value
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - a reference to the key of the group this element belongs to;
    ///  - the current value of the accumulator of the group or `None` if it's the first element
    ///    encountered in the group;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    ///
    /// This is the generic way to perform any operations on a `Grouping`.
    /// It's suggested to use it only to implement custom operations when the already provided ones are not enough.
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<commit_msg>Improved doc for GroupingMap::aggregate<commit_after>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient "group-and-fold" operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
///
// See [`.into_grouping_map()`](../trait.Itertools.html#method.into_grouping_map)
// for more information.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// This is the generic way to perform any operations on a `Grouping`.
    /// It's suggested to use it only to implement custom operations when the already provided ones are not enough.
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<|endoftext|>


<commit_before>//! Implementation of Xen's ring mechanism

use core::{mem, cmp};

use core::marker::PhantomData;

use rlibc::memset;

use alloc_uni::__rust_allocate;

use hal::mmu::{Vaddr, Mfn};

use hal::arch::utils::mb;

use hal::arch::defs::PAGE_SIZE;

use hal::xen::grant::Ref as GrantRef;
use hal::xen::grant::Table as GrantTable;

// Round a 32-bit unsigned constant down to the nearest power of two.
// Taken from xen/interface/io/ring.h
macro_rules! RD2 {
    ($x:expr) => (
        if $x & 0x2 != 0 {
            0x2
        } else {
            $x & 0x1
        }
    );
}

macro_rules! RD4 {
    ($x:expr) => (
        if $x & 0xC != 0 {
            RD2!($x >> 2) << 2
        } else {
            RD2!($x)
        }
    );
}

macro_rules! RD8 {
    ($x:expr) => (
        if $x & 0xF0 != 0 {
            RD4!($x >> 4) << 4
        } else {
            RD4!($x)
        }
    );
}

macro_rules! RD16 {
    ($x:expr) => (
        if $x & 0xFF00 != 0 {
            RD8!($x >> 8) << 8
        } else {
            RD8!($x)
        }
    );
}

macro_rules! RD32 {
    ($x:expr) => (
        if $x & 0xFFFF0000 != 0 {
            RD16!($x >> 16) << 16
        } else {
            RD16!($x)
        }
    );
}

/// Ring index type
pub type Idx = u32;

#[repr(C)]
/// Shared ring page
///
/// Equivalent of struct __name##_sring defined by DEFINE_RING_TYPES
struct XenSharedRing {
    req_prod: Idx,
    req_event: Idx,
    rsp_prod: Idx,
    rsp_event: Idx,
    pad: [u8; 48],
    ring: u8, // Variable length
}

// XXX: deallocate/end grant access on Drop ?
/// Xen's shared ring
///
/// `Req` is the type of the request
///
/// `Resp` is the type of the response
pub struct SharedRing<Req, Resp> {
    sring: *mut XenSharedRing,
    size: usize,
    elt_size: usize,
    grant_ref: Option<GrantRef>,
    _req: PhantomData<Req>,
    _resp: PhantomData<Resp>,
}

impl<Req, Resp> SharedRing<Req, Resp> {
    /// Allocate a new shared ring
    ///
    /// May return None for two reasons:
    /// - `size` is not aligned on PAGE_SIZE
    /// - The system is out of memory
    pub fn new(size: usize) -> Option<SharedRing<Req, Resp>> {
        if size < PAGE_SIZE || size % PAGE_SIZE != 0 {
            return None;
        }

        // Allocate memory for the ring
        let sring = __rust_allocate(size, PAGE_SIZE) as *mut XenSharedRing;

        if sring.is_null() {
            return None;
        }

        // Initialize the ring
        unsafe {
            memset(sring as *mut u8, 0, PAGE_SIZE);

            (*sring).req_prod = 0;
            (*sring).rsp_prod = 0;
            (*sring).req_event = 1;
            (*sring).rsp_event = 1;
        }

        Some(SharedRing {
            sring: sring,
            size: size,
            elt_size: cmp::max(mem::size_of::<Req>(), mem::size_of::<Resp>()),
            grant_ref: None,
            _req: PhantomData,
            _resp: PhantomData,
        })
    }

    /// Create a shared ring from an existing memory area
    pub unsafe fn from_ptr(ptr: *mut u8, size: usize) -> SharedRing<Req, Resp> {
        SharedRing {
            sring: ptr as *mut _,
            size: size,
            elt_size: cmp::max(mem::size_of::<Req>(), mem::size_of::<Resp>()),
            grant_ref: None,
            _req: PhantomData,
            _resp: PhantomData,
        }
    }

    #[inline]
    /// Returns the request production index
    pub fn req_prod(&self) -> Idx {
        unsafe {
            (*self.sring).req_prod
        }
    }

    #[inline]
    /// Returns the response production index
    pub fn rsp_prod(&self) -> Idx {
        unsafe {
            (*self.sring).rsp_prod
        }
    }

    #[inline]
    /// Returns the request event index
    pub fn req_event(&self) -> Idx {
        unsafe {
            (*self.sring).req_event
        }
    }

    #[inline]
    /// Returns the response event index
    pub fn rsp_event(&self) -> Idx {
        unsafe {
            (*self.sring).rsp_event
        }
    }

    /// Set the request production index
    ///
    /// This is unsafe as an invalid index can corrupt the ring
    pub unsafe fn req_prod_set(&mut self, req: Idx) {
        (*self.sring).req_prod = req;
        mb();
    }

    /// Set the response production index
    ///
    /// This is unsafe as an invalid index can corrupt the ring
    pub unsafe fn rsp_prod_set(&mut self, rsp: Idx) {
        (*self.sring).rsp_prod = rsp;
        mb();
    }

    #[inline]
    /// Set the request event index
    pub unsafe fn req_event_set(&mut self, req: Idx) {
        (*self.sring).req_event = req;
    }

    #[inline]
    /// Set the response event index
    pub unsafe fn rsp_event_set(&mut self, rsp: Idx) {
        (*self.sring).rsp_event = rsp;
    }

    /// Returns the size of the ring
    ///
    /// Equivalent to __RING_SIZE
    pub fn size(&self) -> usize {
        let ring_addr = unsafe { &(*self.sring).ring } as *const _ as isize;
        let sring_addr = self.sring as isize;

        RD32!((self.size as isize - ring_addr + sring_addr) as usize /
              self.elt_size)
    }

    /// Grant access to the ring to a foreign domain with id `domid`
    pub fn grant_access(&mut self, domid: u16) -> Option<GrantRef> {
        if let Some(ref r) = self.grant_ref {
            return Some(r.clone());
        }

        match GrantTable::alloc_ref() {
            None => None,
            Some(r) => {
                r.grant_access(domid, Mfn::from(Vaddr::from_ptr(self.sring)),
                               false);

                self.grant_ref = Some(r.clone());

                Some(r)
            }
        }
    }

    #[inline]
    fn ptr_from_index(&mut self, mut idx: usize) -> *mut u8 {
        idx = idx & (self.size() - 1);

        unsafe {
            let ring_ptr: *mut u8 = &mut (*self.sring).ring;

            ring_ptr.offset((idx * self.elt_size) as isize) as *mut u8
        }
    }

    /// Get a reference over the request at position `idx`
    pub fn request_from_index(&mut self, idx: usize) -> &mut Req {
        unsafe {
            &mut *(self.ptr_from_index(idx) as *mut Req)
        }
    }

    /// Get a reference over the response at position `idx`
    pub fn response_from_index(&mut self, idx: usize) -> &mut Resp {
        unsafe {
            &mut *(self.ptr_from_index(idx) as *mut Resp)
        }
    }
}
<commit_msg>xen/ring: Add FrontRing implementation<commit_after>//! Implementation of Xen's ring mechanism

use core::{mem, cmp};

use core::marker::PhantomData;

use rlibc::memset;

use alloc_uni::__rust_allocate;

use hal::mmu::{Vaddr, Mfn};

use hal::arch::utils::{mb, wmb};

use hal::arch::defs::PAGE_SIZE;

use hal::xen::grant::Ref as GrantRef;
use hal::xen::grant::Table as GrantTable;

// Round a 32-bit unsigned constant down to the nearest power of two.
// Taken from xen/interface/io/ring.h
macro_rules! RD2 {
    ($x:expr) => (
        if $x & 0x2 != 0 {
            0x2
        } else {
            $x & 0x1
        }
    );
}

macro_rules! RD4 {
    ($x:expr) => (
        if $x & 0xC != 0 {
            RD2!($x >> 2) << 2
        } else {
            RD2!($x)
        }
    );
}

macro_rules! RD8 {
    ($x:expr) => (
        if $x & 0xF0 != 0 {
            RD4!($x >> 4) << 4
        } else {
            RD4!($x)
        }
    );
}

macro_rules! RD16 {
    ($x:expr) => (
        if $x & 0xFF00 != 0 {
            RD8!($x >> 8) << 8
        } else {
            RD8!($x)
        }
    );
}

macro_rules! RD32 {
    ($x:expr) => (
        if $x & 0xFFFF0000 != 0 {
            RD16!($x >> 16) << 16
        } else {
            RD16!($x)
        }
    );
}

/// Ring index type
pub type Idx = u32;

#[repr(C)]
/// Shared ring page
///
/// Equivalent of struct __name##_sring defined by DEFINE_RING_TYPES
struct XenSharedRing {
    req_prod: Idx,
    req_event: Idx,
    rsp_prod: Idx,
    rsp_event: Idx,
    pad: [u8; 48],
    ring: u8, // Variable length
}

// XXX: deallocate/end grant access on Drop ?
/// Xen's shared ring
///
/// `Req` is the type of the request
///
/// `Resp` is the type of the response
pub struct SharedRing<Req, Resp> {
    sring: *mut XenSharedRing,
    size: usize,
    elt_size: usize,
    grant_ref: Option<GrantRef>,
    _req: PhantomData<Req>,
    _resp: PhantomData<Resp>,
}

impl<Req, Resp> SharedRing<Req, Resp> {
    /// Allocate a new shared ring
    ///
    /// May return None for two reasons:
    /// - `size` is not aligned on PAGE_SIZE
    /// - The system is out of memory
    pub fn new(size: usize) -> Option<SharedRing<Req, Resp>> {
        if size < PAGE_SIZE || size % PAGE_SIZE != 0 {
            return None;
        }

        // Allocate memory for the ring
        let sring = __rust_allocate(size, PAGE_SIZE) as *mut XenSharedRing;

        if sring.is_null() {
            return None;
        }

        // Initialize the ring
        unsafe {
            memset(sring as *mut u8, 0, PAGE_SIZE);

            (*sring).req_prod = 0;
            (*sring).rsp_prod = 0;
            (*sring).req_event = 1;
            (*sring).rsp_event = 1;
        }

        Some(SharedRing {
            sring: sring,
            size: size,
            elt_size: cmp::max(mem::size_of::<Req>(), mem::size_of::<Resp>()),
            grant_ref: None,
            _req: PhantomData,
            _resp: PhantomData,
        })
    }

    /// Create a shared ring from an existing memory area
    pub unsafe fn from_ptr(ptr: *mut u8, size: usize) -> SharedRing<Req, Resp> {
        SharedRing {
            sring: ptr as *mut _,
            size: size,
            elt_size: cmp::max(mem::size_of::<Req>(), mem::size_of::<Resp>()),
            grant_ref: None,
            _req: PhantomData,
            _resp: PhantomData,
        }
    }

    #[inline]
    /// Returns the request production index
    pub fn req_prod(&self) -> Idx {
        unsafe {
            (*self.sring).req_prod
        }
    }

    #[inline]
    /// Returns the response production index
    pub fn rsp_prod(&self) -> Idx {
        unsafe {
            (*self.sring).rsp_prod
        }
    }

    #[inline]
    /// Returns the request event index
    pub fn req_event(&self) -> Idx {
        unsafe {
            (*self.sring).req_event
        }
    }

    #[inline]
    /// Returns the response event index
    pub fn rsp_event(&self) -> Idx {
        unsafe {
            (*self.sring).rsp_event
        }
    }

    /// Set the request production index
    ///
    /// This is unsafe as an invalid index can corrupt the ring
    pub unsafe fn req_prod_set(&mut self, req: Idx) {
        (*self.sring).req_prod = req;
        mb();
    }

    /// Set the response production index
    ///
    /// This is unsafe as an invalid index can corrupt the ring
    pub unsafe fn rsp_prod_set(&mut self, rsp: Idx) {
        (*self.sring).rsp_prod = rsp;
        mb();
    }

    #[inline]
    /// Set the request event index
    pub unsafe fn req_event_set(&mut self, req: Idx) {
        (*self.sring).req_event = req;
    }

    #[inline]
    /// Set the response event index
    pub unsafe fn rsp_event_set(&mut self, rsp: Idx) {
        (*self.sring).rsp_event = rsp;
    }

    /// Returns the size of the ring
    ///
    /// Equivalent to __RING_SIZE
    pub fn size(&self) -> usize {
        let ring_addr = unsafe { &(*self.sring).ring } as *const _ as isize;
        let sring_addr = self.sring as isize;

        RD32!((self.size as isize - ring_addr + sring_addr) as usize /
              self.elt_size)
    }

    /// Grant access to the ring to a foreign domain with id `domid`
    pub fn grant_access(&mut self, domid: u16) -> Option<GrantRef> {
        if let Some(ref r) = self.grant_ref {
            return Some(r.clone());
        }

        match GrantTable::alloc_ref() {
            None => None,
            Some(r) => {
                r.grant_access(domid, Mfn::from(Vaddr::from_ptr(self.sring)),
                               false);

                self.grant_ref = Some(r.clone());

                Some(r)
            }
        }
    }

    #[inline]
    fn ptr_from_index(&mut self, mut idx: usize) -> *mut u8 {
        idx = idx & (self.size() - 1);

        unsafe {
            let ring_ptr: *mut u8 = &mut (*self.sring).ring;

            ring_ptr.offset((idx * self.elt_size) as isize) as *mut u8
        }
    }

    /// Get a reference over the request at position `idx`
    pub fn request_from_index(&mut self, idx: usize) -> &mut Req {
        unsafe {
            &mut *(self.ptr_from_index(idx) as *mut Req)
        }
    }

    /// Get a reference over the response at position `idx`
    pub fn response_from_index(&mut self, idx: usize) -> &mut Resp {
        unsafe {
            &mut *(self.ptr_from_index(idx) as *mut Resp)
        }
    }
}

/// Xen's front end ring
///
/// `Req` is the type of the request
///
/// `Resp` is the type of the response
pub struct FrontRing<Req, Resp> {
    req_prod_pvt: Idx,
    rsp_cons_pvt: Idx,
    nr_ents: u32,
    sring: SharedRing<Req, Resp>,
}

impl<Req, Resp> FrontRing<Req, Resp> {
    /// Create a new frond end ring that operates on the shared ring `sring`
    pub fn new(sring: SharedRing<Req, Resp>) -> Self {
        FrontRing {
            req_prod_pvt: 0,
            rsp_cons_pvt: 0,
            nr_ents: sring.size() as u32,
            sring: sring,
        }
    }

    #[inline]
    /// Returns the size of the ring (i.e. the number of entries it contains)
    pub fn size(&self) -> usize {
        self.nr_ents as usize
    }

    #[inline]
    /// Returns the request production index
    pub fn req_prod(&self) -> Idx {
        self.req_prod_pvt
    }

    #[inline]
    /// Returns the response consumer index
    pub fn rsp_cons(&self) -> Idx {
        self.rsp_cons_pvt
    }

    #[inline]
    /// Returns the request production index as mutable
    ///
    /// This is unsafe as an invalid index can corrupt the ring
    pub unsafe fn req_prod_mut(&mut self) -> &mut Idx {
        &mut self.req_prod_pvt
    }

    #[inline]
    /// Returns the response production index as mutable
    ///
    /// This is unsafe as an invalid index can corrupt the ring
    pub unsafe fn rsp_cons_mut(&mut self) -> &mut Idx {
        &mut self.rsp_cons_pvt
    }

    #[inline]
    /// Returns a mutable reference over the underlying shared ring
    pub unsafe fn sring_mut(&mut self) -> &mut SharedRing<Req, Resp> {
        &mut self.sring
    }

    #[inline]
    /// Returns true if the ring has unconsumed responses
    ///
    /// Equivalent to RING_HAS_UNCONSUMED_RESPONSES
    pub fn has_unconsumed_responses(&self) -> bool {
        self.sring.rsp_prod() - self.rsp_cons_pvt > 0
    }

    /// Push requests down to the shared ring.
    ///
    /// This function will return true if the other end of the ring should be
    /// notified
    ///
    /// Equivalent to RING_PUSH_REQUESTS_AND_CHECK_NOTIFY
    pub fn push_requests(&mut self) -> bool {
        let old = self.sring.req_prod();
        let new = self.req_prod_pvt;

        wmb();

        unsafe {
            self.sring.req_prod_set(new);
        }
        mb();

        (new - self.sring.req_event()) < (new - old)
    }

    /// Returns true if there is still work to do
    ///
    /// Equivalent to RING_FINAL_CHECK_FOR_RESPONSES
    pub fn final_check_for_responses(&mut self) -> bool {
        if self.has_unconsumed_responses() {
            return true;
        }

        let rsp_event = self.rsp_cons() + 1;

        unsafe {
            self.sring.rsp_event_set(rsp_event);
        }

        self.has_unconsumed_responses()
    }
}
<|endoftext|>


<commit_before>/*
 * Implemenation of a bitfield as a vec. Only
 * supports bytes (Vec<u8>) as the underlying
 * storage.
 *
 * A future implementation should be more efficient,
 * this is just to get the job done for now.
 */
extern crate rlp;
use self::rlp::{ RlpStream, Encodable };

pub struct BooleanBitfield{
    vec: Vec<u8>
}

impl BooleanBitfield {
    pub fn new() -> Self {
        Self {
            vec: vec![]
        }
    }

    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            vec: Vec::with_capacity(capacity)
        }
    }

    // Output the bitfield as a big-endian vec of u8
    pub fn to_be_vec(&self) -> Vec<u8> {
        let mut o = self.vec.clone();
        o.reverse();
        o
    }

    pub fn get_bit(&self, i: &usize) -> bool {
        self.get_bit_on_byte(*i % 8, *i / 8)
    }

    fn get_bit_on_byte(&self, bit: usize, byte: usize) -> bool {
        assert!(bit < 8);
        if byte >= self.vec.len() {
            false
        } else {
             self.vec[byte] & (1 << (bit as u8)) != 0
        }
    }

    pub fn set_bit(&mut self, bit: &usize, to: &bool) {
        self.set_bit_on_byte(*bit % 8, *bit / 8, to);
    }

    fn set_bit_on_byte(&mut self, bit: usize, byte: usize, val: &bool) {
        assert!(bit < 8);
        if byte >= self.vec.len() {
            self.vec.resize(byte + 1, 0);
        }
        match val {
            true =>  self.vec[byte] = self.vec[byte] |  (1 << (bit as u8)),
            false => self.vec[byte] = self.vec[byte] & !(1 << (bit as u8))
        }
    }
}

impl Encodable for BooleanBitfield {
    // TODO: ensure this is a sensible method of encoding
    // the bitfield. Currently, it is treated as a list of
    // bytes not as a string. I do not have any guidance as
    // to which method is correct -- don't follow my lead
    // without seeking authoritative advice.
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&self.to_be_vec());
    }
}

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

    #[test]
    fn test_bitfield_set() {
        let mut b = BooleanBitfield::new();
        b.set_bit(&0, &false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(&7, &true);
        assert_eq!(b.to_be_vec(), [128]);
        b.set_bit(&7, &false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(&7, &true);
        b.set_bit(&0, &true);
        assert_eq!(b.to_be_vec(), [129]);
        b.set_bit(&7, &false);
        assert_eq!(b.to_be_vec(), [1]);

        b = BooleanBitfield::new();
        b.set_bit(&8, &true);
        assert_eq!(b.to_be_vec(), [1, 0]);
        b.set_bit(&8, &false);
        assert_eq!(b.to_be_vec(), [0, 0]);

        b = BooleanBitfield::new();
        b.set_bit(&15, &true);
        assert_eq!(b.to_be_vec(), [128, 0]);
        b.set_bit(&15, &false);
        assert_eq!(b.to_be_vec(), [0, 0]);

        b = BooleanBitfield::new();
        b.set_bit(&8, &true);
        b.set_bit(&15, &true);
        assert_eq!(b.to_be_vec(), [129, 0]);
        b.set_bit(&15, &false);
        assert_eq!(b.to_be_vec(), [1, 0]);
    }

    #[test]
    fn test_bitfield_get() {
        let test_nums = vec![0, 8, 15, 42, 1337];
        for i in test_nums {
            let mut b = BooleanBitfield::new();
            assert_eq!(b.get_bit(&i), false);
            b.set_bit(&i, &true);
            assert_eq!(b.get_bit(&i), true);
            b.set_bit(&i, &true);
        }
    }

    #[test]
    fn test_bitfield_rlp_serialization() {
        let mut b = BooleanBitfield::new();
        b.set_bit(&15, &true);
        let e = rlp::encode(&b);
        assert_eq!(e[0], 130);
        assert_eq!(e[1], 128);
        assert_eq!(e[2], 0);
    }
}
<commit_msg>Add num_true_bits to bitfield<commit_after>/*
 * Implemenation of a bitfield as a vec. Only
 * supports bytes (Vec<u8>) as the underlying
 * storage.
 *
 * A future implementation should be more efficient,
 * this is just to get the job done for now.
 */
extern crate rlp;
use self::rlp::{ RlpStream, Encodable };

pub struct BooleanBitfield{
    vec: Vec<u8>
}

impl BooleanBitfield {
    pub fn new() -> Self {
        Self {
            vec: vec![]
        }
    }

    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            vec: Vec::with_capacity(capacity)
        }
    }

    // Output the bitfield as a big-endian vec of u8.
    pub fn to_be_vec(&self) -> Vec<u8> {
        let mut o = self.vec.clone();
        o.reverse();
        o
    }

    pub fn get_bit(&self, i: &usize) -> bool {
        self.get_bit_on_byte(*i % 8, *i / 8)
    }

    fn get_bit_on_byte(&self, bit: usize, byte: usize) -> bool {
        assert!(bit < 8);
        if byte >= self.vec.len() {
            false
        } else {
             self.vec[byte] & (1 << (bit as u8)) != 0
        }
    }

    pub fn set_bit(&mut self, bit: &usize, to: &bool) {
        self.set_bit_on_byte(*bit % 8, *bit / 8, to);
    }

    fn set_bit_on_byte(&mut self, bit: usize, byte: usize, val: &bool) {
        assert!(bit < 8);
        if byte >= self.vec.len() {
            self.vec.resize(byte + 1, 0);
        }
        match val {
            true =>  self.vec[byte] = self.vec[byte] |  (1 << (bit as u8)),
            false => self.vec[byte] = self.vec[byte] & !(1 << (bit as u8))
        }
    }

    // Return the total number of bits set to true.
    pub fn num_true_bits(&mut self) -> u64 {
        let mut count: u64 = 0;
        for byte in &self.vec {
            for bit in 0..8 {
                if byte & (1 << (bit as u8)) != 0 {
                    count += 1;
                }
            }
        }
        count
    }
}

impl Encodable for BooleanBitfield {
    // TODO: ensure this is a sensible method of encoding
    // the bitfield. Currently, it is treated as a list of
    // bytes not as a string. I do not have any guidance as
    // to which method is correct -- don't follow my lead
    // without seeking authoritative advice.
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&self.to_be_vec());
    }
}

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

    #[test]
    fn test_bitfield_set() {
        let mut b = BooleanBitfield::new();
        b.set_bit(&0, &false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(&7, &true);
        assert_eq!(b.to_be_vec(), [128]);
        b.set_bit(&7, &false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(&7, &true);
        b.set_bit(&0, &true);
        assert_eq!(b.to_be_vec(), [129]);
        b.set_bit(&7, &false);
        assert_eq!(b.to_be_vec(), [1]);

        b = BooleanBitfield::new();
        b.set_bit(&8, &true);
        assert_eq!(b.to_be_vec(), [1, 0]);
        b.set_bit(&8, &false);
        assert_eq!(b.to_be_vec(), [0, 0]);

        b = BooleanBitfield::new();
        b.set_bit(&15, &true);
        assert_eq!(b.to_be_vec(), [128, 0]);
        b.set_bit(&15, &false);
        assert_eq!(b.to_be_vec(), [0, 0]);

        b = BooleanBitfield::new();
        b.set_bit(&8, &true);
        b.set_bit(&15, &true);
        assert_eq!(b.to_be_vec(), [129, 0]);
        b.set_bit(&15, &false);
        assert_eq!(b.to_be_vec(), [1, 0]);
    }

    #[test]
    fn test_bitfield_get() {
        let test_nums = vec![0, 8, 15, 42, 1337];
        for i in test_nums {
            let mut b = BooleanBitfield::new();
            assert_eq!(b.get_bit(&i), false);
            b.set_bit(&i, &true);
            assert_eq!(b.get_bit(&i), true);
            b.set_bit(&i, &true);
        }
    }

    #[test]
    fn test_bitfield_rlp_serialization() {
        let mut b = BooleanBitfield::new();
        b.set_bit(&15, &true);
        let e = rlp::encode(&b);
        assert_eq!(e[0], 130);
        assert_eq!(e[1], 128);
        assert_eq!(e[2], 0);
    }

    #[test]
    fn test_bitfield_num_true_bits() {
        let mut b = BooleanBitfield::new();
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(&15, &true);
        assert_eq!(b.num_true_bits(), 1);
        b.set_bit(&15, &false);
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(&0, &true);
        b.set_bit(&7, &true);
        b.set_bit(&8, &true);
        b.set_bit(&1337, &true);
        assert_eq!(b.num_true_bits(), 4);
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alex Lyon <arcterus@mail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) tstr sigstr cmdname setpgid sigchld

#[macro_use]
extern crate uucore;

extern crate clap;

use clap::{crate_version, App, AppSettings, Arg};
use std::io::ErrorKind;
use std::process::{Command, Stdio};
use std::time::Duration;
use uucore::process::ChildExt;
use uucore::signals::{signal_by_name_or_value, signal_name_by_value};
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION.";

fn get_usage() -> String {
    format!("{0} [OPTION] DURATION COMMAND...", executable!())
}

const ERR_EXIT_STATUS: i32 = 125;

pub mod options {
    pub static FOREGROUND: &str = "foreground";
    pub static KILL_AFTER: &str = "kill-after";
    pub static SIGNAL: &str = "signal";
    pub static PRESERVE_STATUS: &str = "preserve-status";
    pub static VERBOSE: &str = "verbose";

    // Positional args.
    pub static DURATION: &str = "duration";
    pub static COMMAND: &str = "command";
}

struct Config {
    foreground: bool,
    kill_after: Option<Duration>,
    signal: usize,
    duration: Duration,
    preserve_status: bool,
    verbose: bool,

    command: Vec<String>,
}

impl Config {
    fn from(options: clap::ArgMatches) -> Config {
        let signal = match options.value_of(options::SIGNAL) {
            Some(signal_) => {
                let signal_result = signal_by_name_or_value(signal_);
                match signal_result {
                    None => {
                        unreachable!("invalid signal '{}'", signal_);
                    }
                    Some(signal_value) => signal_value,
                }
            }
            _ => uucore::signals::signal_by_name_or_value("TERM").unwrap(),
        };

        let kill_after = options
            .value_of(options::KILL_AFTER)
            .map(|time| uucore::parse_time::from_str(time).unwrap());

        let duration: Duration =
            uucore::parse_time::from_str(options.value_of(options::DURATION).unwrap()).unwrap();

        let preserve_status: bool = options.is_present(options::PRESERVE_STATUS);
        let foreground = options.is_present(options::FOREGROUND);
        let verbose = options.is_present(options::VERBOSE);

        let command = options
            .values_of(options::COMMAND)
            .unwrap()
            .map(String::from)
            .collect::<Vec<_>>();

        Config {
            foreground,
            kill_after,
            signal,
            duration,
            preserve_status,
            command,
            verbose,
        }
    }
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();

    let app = App::new("timeout")
        .version(crate_version!())
        .usage(&usage[..])
        .about(ABOUT)
        .arg(
            Arg::with_name(options::FOREGROUND)
                .long(options::FOREGROUND)
                .help("when not running timeout directly from a shell prompt, allow COMMAND to read from the TTY and get TTY signals; in this mode, children of COMMAND will not be timed out")
        )
        .arg(
            Arg::with_name(options::KILL_AFTER)
                .short("k")
                .takes_value(true))
        .arg(
            Arg::with_name(options::PRESERVE_STATUS)
                .long(options::PRESERVE_STATUS)
                .help("exit with the same status as COMMAND, even when the command times out")
        )
        .arg(
            Arg::with_name(options::SIGNAL)
                .short("s")
                .long(options::SIGNAL)
                .help("specify the signal to be sent on timeout; SIGNAL may be a name like 'HUP' or a number; see 'kill -l' for a list of signals")
                .takes_value(true)
        )
        .arg(
            Arg::with_name(options::VERBOSE)
              .short("v")
              .long(options::VERBOSE)
              .help("diagnose to stderr any signal sent upon timeout")
        )
        .arg(
            Arg::with_name(options::DURATION)
                .index(1)
                .required(true)
        )
        .arg(
            Arg::with_name(options::COMMAND)
                .index(2)
                .required(true)
                .multiple(true)
        )
        .setting(AppSettings::TrailingVarArg);

    let matches = app.get_matches_from(args);

    let config = Config::from(matches);
    timeout(
        &config.command,
        config.duration,
        config.signal,
        config.kill_after,
        config.foreground,
        config.preserve_status,
        config.verbose,
    )
}

/// Remove pre-existing SIGCHLD handlers that would make waiting for the child's exit code fail.
fn unblock_sigchld() {
    unsafe {
        nix::sys::signal::signal(
            nix::sys::signal::Signal::SIGCHLD,
            nix::sys::signal::SigHandler::SigDfl,
        )
        .unwrap();
    }
}

/// TODO: Improve exit codes, and make them consistent with the GNU Coreutils exit codes.

fn timeout(
    cmd: &[String],
    duration: Duration,
    signal: usize,
    kill_after: Option<Duration>,
    foreground: bool,
    preserve_status: bool,
    verbose: bool,
) -> i32 {
    if !foreground {
        unsafe { libc::setpgid(0, 0) };
    }
    let mut process = match Command::new(&cmd[0])
        .args(&cmd[1..])
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .spawn()
    {
        Ok(p) => p,
        Err(err) => {
            show_error!("failed to execute process: {}", err);
            if err.kind() == ErrorKind::NotFound {
                // FIXME: not sure which to use
                return 127;
            } else {
                // FIXME: this may not be 100% correct...
                return 126;
            }
        }
    };
    unblock_sigchld();
    match process.wait_or_timeout(duration) {
        Ok(Some(status)) => status.code().unwrap_or_else(|| status.signal().unwrap()),
        Ok(None) => {
            if verbose {
                show_error!(
                    "sending signal {} to command '{}'",
                    signal_name_by_value(signal).unwrap(),
                    cmd[0]
                );
            }
            return_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
            if let Some(kill_after) = kill_after {
                match process.wait_or_timeout(kill_after) {
                    Ok(Some(status)) => {
                        if preserve_status {
                            status.code().unwrap_or_else(|| status.signal().unwrap())
                        } else {
                            124
                        }
                    }
                    Ok(None) => {
                        if verbose {
                            show_error!("sending signal KILL to command '{}'", cmd[0]);
                        }
                        return_if_err!(
                            ERR_EXIT_STATUS,
                            process.send_signal(
                                uucore::signals::signal_by_name_or_value("KILL").unwrap()
                            )
                        );
                        return_if_err!(ERR_EXIT_STATUS, process.wait());
                        137
                    }
                    Err(_) => 124,
                }
            } else {
                124
            }
        }
        Err(_) => {
            return_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
            ERR_EXIT_STATUS
        }
    }
}
<commit_msg>Fix a clippy warning<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alex Lyon <arcterus@mail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) tstr sigstr cmdname setpgid sigchld

#[macro_use]
extern crate uucore;

extern crate clap;

use clap::{crate_version, App, AppSettings, Arg};
use std::io::ErrorKind;
use std::process::{Command, Stdio};
use std::time::Duration;
use uucore::process::ChildExt;
use uucore::signals::{signal_by_name_or_value, signal_name_by_value};
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION.";

fn get_usage() -> String {
    format!("{0} [OPTION] DURATION COMMAND...", executable!())
}

const ERR_EXIT_STATUS: i32 = 125;

pub mod options {
    pub static FOREGROUND: &str = "foreground";
    pub static KILL_AFTER: &str = "kill-after";
    pub static SIGNAL: &str = "signal";
    pub static PRESERVE_STATUS: &str = "preserve-status";
    pub static VERBOSE: &str = "verbose";

    // Positional args.
    pub static DURATION: &str = "duration";
    pub static COMMAND: &str = "command";
}

struct Config {
    foreground: bool,
    kill_after: Option<Duration>,
    signal: usize,
    duration: Duration,
    preserve_status: bool,
    verbose: bool,

    command: Vec<String>,
}

impl Config {
    fn from(options: clap::ArgMatches) -> Config {
        let signal = match options.value_of(options::SIGNAL) {
            Some(signal_) => {
                let signal_result = signal_by_name_or_value(signal_);
                match signal_result {
                    None => {
                        unreachable!("invalid signal '{}'", signal_);
                    }
                    Some(signal_value) => signal_value,
                }
            }
            _ => uucore::signals::signal_by_name_or_value("TERM").unwrap(),
        };

        let kill_after = options
            .value_of(options::KILL_AFTER)
            .map(|time| uucore::parse_time::from_str(time).unwrap());

        let duration: Duration =
            uucore::parse_time::from_str(options.value_of(options::DURATION).unwrap()).unwrap();

        let preserve_status: bool = options.is_present(options::PRESERVE_STATUS);
        let foreground = options.is_present(options::FOREGROUND);
        let verbose = options.is_present(options::VERBOSE);

        let command = options
            .values_of(options::COMMAND)
            .unwrap()
            .map(String::from)
            .collect::<Vec<_>>();

        Config {
            foreground,
            kill_after,
            signal,
            duration,
            preserve_status,
            verbose,
            command,
        }
    }
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();

    let app = App::new("timeout")
        .version(crate_version!())
        .usage(&usage[..])
        .about(ABOUT)
        .arg(
            Arg::with_name(options::FOREGROUND)
                .long(options::FOREGROUND)
                .help("when not running timeout directly from a shell prompt, allow COMMAND to read from the TTY and get TTY signals; in this mode, children of COMMAND will not be timed out")
        )
        .arg(
            Arg::with_name(options::KILL_AFTER)
                .short("k")
                .takes_value(true))
        .arg(
            Arg::with_name(options::PRESERVE_STATUS)
                .long(options::PRESERVE_STATUS)
                .help("exit with the same status as COMMAND, even when the command times out")
        )
        .arg(
            Arg::with_name(options::SIGNAL)
                .short("s")
                .long(options::SIGNAL)
                .help("specify the signal to be sent on timeout; SIGNAL may be a name like 'HUP' or a number; see 'kill -l' for a list of signals")
                .takes_value(true)
        )
        .arg(
            Arg::with_name(options::VERBOSE)
              .short("v")
              .long(options::VERBOSE)
              .help("diagnose to stderr any signal sent upon timeout")
        )
        .arg(
            Arg::with_name(options::DURATION)
                .index(1)
                .required(true)
        )
        .arg(
            Arg::with_name(options::COMMAND)
                .index(2)
                .required(true)
                .multiple(true)
        )
        .setting(AppSettings::TrailingVarArg);

    let matches = app.get_matches_from(args);

    let config = Config::from(matches);
    timeout(
        &config.command,
        config.duration,
        config.signal,
        config.kill_after,
        config.foreground,
        config.preserve_status,
        config.verbose,
    )
}

/// Remove pre-existing SIGCHLD handlers that would make waiting for the child's exit code fail.
fn unblock_sigchld() {
    unsafe {
        nix::sys::signal::signal(
            nix::sys::signal::Signal::SIGCHLD,
            nix::sys::signal::SigHandler::SigDfl,
        )
        .unwrap();
    }
}

/// TODO: Improve exit codes, and make them consistent with the GNU Coreutils exit codes.

fn timeout(
    cmd: &[String],
    duration: Duration,
    signal: usize,
    kill_after: Option<Duration>,
    foreground: bool,
    preserve_status: bool,
    verbose: bool,
) -> i32 {
    if !foreground {
        unsafe { libc::setpgid(0, 0) };
    }
    let mut process = match Command::new(&cmd[0])
        .args(&cmd[1..])
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .spawn()
    {
        Ok(p) => p,
        Err(err) => {
            show_error!("failed to execute process: {}", err);
            if err.kind() == ErrorKind::NotFound {
                // FIXME: not sure which to use
                return 127;
            } else {
                // FIXME: this may not be 100% correct...
                return 126;
            }
        }
    };
    unblock_sigchld();
    match process.wait_or_timeout(duration) {
        Ok(Some(status)) => status.code().unwrap_or_else(|| status.signal().unwrap()),
        Ok(None) => {
            if verbose {
                show_error!(
                    "sending signal {} to command '{}'",
                    signal_name_by_value(signal).unwrap(),
                    cmd[0]
                );
            }
            return_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
            if let Some(kill_after) = kill_after {
                match process.wait_or_timeout(kill_after) {
                    Ok(Some(status)) => {
                        if preserve_status {
                            status.code().unwrap_or_else(|| status.signal().unwrap())
                        } else {
                            124
                        }
                    }
                    Ok(None) => {
                        if verbose {
                            show_error!("sending signal KILL to command '{}'", cmd[0]);
                        }
                        return_if_err!(
                            ERR_EXIT_STATUS,
                            process.send_signal(
                                uucore::signals::signal_by_name_or_value("KILL").unwrap()
                            )
                        );
                        return_if_err!(ERR_EXIT_STATUS, process.wait());
                        137
                    }
                    Err(_) => 124,
                }
            } else {
                124
            }
        }
        Err(_) => {
            return_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
            ERR_EXIT_STATUS
        }
    }
}
<|endoftext|>