<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,
    Frameable,
    Labelable,
    Positionable,
    Sizeable,
    Theme,
    Toggle,
    Ui,
    Widget,
};
use conrod::color::{black, grayscale, 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
}

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();
        let mut rebind = self.translator.clone().into_rebind();

        // declare widget ids
        widget_ids! {
            X_INVERT_TOGGLE,
            Y_INVERT_TOGGLE
        }

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

            Toggle::new(rebind.get_x_motion_inverted())
                .xy(-350.0, 260.0)
                .dimensions(80.0, 40.0)
                .color(grayscale(0.4))
                .frame(1.0)
                .label(&"Invert X")
                .label_color(self.bg_color.plain_contrast())
                .label_font_size(16)
                .react(|b| rebind.set_x_motion_inverted(b))
                .set(X_INVERT_TOGGLE, ui);

            Toggle::new(rebind.get_y_motion_inverted())
                .xy(-350.0, 200.0)
                .dimensions(80.0, 40.0)
                .color(grayscale(0.4))
                .frame(1.0)
                .label(&"Invert Y")
                .label_color(self.bg_color.plain_contrast())
                .label_font_size(16)
                .react(|b| rebind.set_y_motion_inverted(b))
                .set(Y_INVERT_TOGGLE, 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));
        }

        self.translator = rebind.into();
    }
}

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("rebind-example", 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)
        .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() {
        app.ui.borrow_mut().handle_event(&e);
        match e {
            Event::Input(i) => { app.input(&i); },
            Event::Update(u) => { app.update(&u); },
            Event::Render(r) => { app.render(&r); },
            _ => { }
        }
    }
}<commit_msg>Move very specific import statements regarding keyboard keys close to where the translator is created<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,
    Frameable,
    Labelable,
    Positionable,
    Sizeable,
    Theme,
    Toggle,
    Ui,
    Widget,
};
use conrod::color::{black, grayscale, 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::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
}

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();
        let mut rebind = self.translator.clone().into_rebind();

        // declare widget ids
        widget_ids! {
            X_INVERT_TOGGLE,
            Y_INVERT_TOGGLE
        }

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

            Toggle::new(rebind.get_x_motion_inverted())
                .xy(-350.0, 260.0)
                .dimensions(80.0, 40.0)
                .color(grayscale(0.4))
                .frame(1.0)
                .label(&"Invert X")
                .label_color(self.bg_color.plain_contrast())
                .label_font_size(16)
                .react(|b| rebind.set_x_motion_inverted(b))
                .set(X_INVERT_TOGGLE, ui);

            Toggle::new(rebind.get_y_motion_inverted())
                .xy(-350.0, 200.0)
                .dimensions(80.0, 40.0)
                .color(grayscale(0.4))
                .frame(1.0)
                .label(&"Invert Y")
                .label_color(self.bg_color.plain_contrast())
                .label_font_size(16)
                .react(|b| rebind.set_y_motion_inverted(b))
                .set(Y_INVERT_TOGGLE, 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));
        }

        self.translator = rebind.into();
    }
}

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("rebind-example", 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 = {
        use piston::input::keyboard::Key;
        use piston::input::Button::Keyboard;
        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 = {
        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() {
        app.ui.borrow_mut().handle_event(&e);
        match e {
            Event::Input(i) => { app.input(&i); },
            Event::Update(u) => { app.update(&u); },
            Event::Render(r) => { app.render(&r); },
            _ => { }
        }
    }
}<|endoftext|>


<commit_before>//! Termination tests.
//!
//! This macro tests that instances within some kind of memory region can be terminated properly
//! using a remote kill switch. See
//! [`KillSwitch::terminate`](struct.KillSwitch.html#method.terminate) for more information.
#[macro_export]
macro_rules! timeout_tests {
    ( $TestRegion:path ) => {
        use lucet_runtime::vmctx::{lucet_vmctx, Vmctx};
        use lucet_runtime::{
            lucet_hostcall, lucet_hostcall_terminate, DlModule, Error, FaultDetails, Instance,
            KillError, KillSuccess, Limits, Module, Region, RunResult, SignalBehavior,
            TerminationDetails, TrapCode, YieldedVal,
        };
        use nix::sys::mman::{mmap, MapFlags, ProtFlags};
        use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal};
        use nix::sys::wait::{waitpid, WaitStatus};
        use nix::unistd::{fork, ForkResult};
        use std::ptr;
        use std::sync::{Arc, Mutex};
        use std::thread;
        use std::time::Duration;
        use $TestRegion as TestRegion;
        use $crate::build::test_module_c;
        use $crate::helpers::{FunctionPointer, MockExportBuilder, MockModuleBuilder};

        /// Return a mock module so that we can test termination behavior.
        ///
        /// See `lucet_runtime_internals::module::mock::MockModuleBuilder` for more information.
        pub fn mock_timeout_module() -> Arc<dyn Module> {
            extern "C" fn onetwothree(_vmctx: *mut lucet_vmctx) -> std::os::raw::c_int {
                123
            }

            extern "C" fn infinite_loop(_vmctx: *mut lucet_vmctx) -> () {
                loop {}
            }

            extern "C" fn do_nothing(_vmctx: *mut lucet_vmctx) -> () {}

            extern "C" fn run_slow_hostcall(vmctx: *mut lucet_vmctx) -> bool {
                extern "C" {
                    fn slow_hostcall(vmctx: *mut lucet_vmctx) -> bool;
                }
                unsafe { slow_hostcall(vmctx) }
            }

            extern "C" fn run_yielding_hostcall(vmctx: *mut lucet_vmctx) -> () {
                extern "C" {
                    fn yielding_hostcall(vmctx: *mut lucet_vmctx) -> ();
                }
                unsafe { yielding_hostcall(vmctx) }
            }

            MockModuleBuilder::new()
                .with_export_func(MockExportBuilder::new(
                    "infinite_loop",
                    FunctionPointer::from_usize(infinite_loop as usize),
                ))
                .with_export_func(MockExportBuilder::new(
                    "do_nothing",
                    FunctionPointer::from_usize(do_nothing as usize),
                ))
                .with_export_func(MockExportBuilder::new(
                    "onetwothree",
                    FunctionPointer::from_usize(onetwothree as usize),
                ))
                .with_export_func(MockExportBuilder::new(
                    "run_slow_hostcall",
                    FunctionPointer::from_usize(run_slow_hostcall as usize),
                ))
                .with_export_func(MockExportBuilder::new(
                    "run_yielding_hostcall",
                    FunctionPointer::from_usize(run_yielding_hostcall as usize),
                ))
                .build()
        }

        /// This test hostcall will wait for 200 milliseconds before returning `true`.
        /// This is used to make a window of time so we can timeout inside of a hostcall.
        #[lucet_hostcall]
        #[no_mangle]
        pub fn slow_hostcall(vmctx: &mut Vmctx) -> bool {
            thread::sleep(Duration::from_millis(200));
            true
        }

        /// This test hostcall will immediately yield. This is used to test termination of a
        /// yielded instance.
        #[lucet_hostcall]
        #[no_mangle]
        pub fn yielding_hostcall(vmctx: &mut Vmctx) {
            vmctx.yield_();
        }

        /// A convenience wrapper around running our mock timeout module's `onetwothree` function,
        /// and asserting that it returned the expected result.
        fn run_onetwothree(inst: &mut Instance) {
            let retval = inst
                .run("onetwothree", &[])
                .expect("instance runs")
                .unwrap_returned();
            assert_eq!(libc::c_int::from(retval), 123);
        }

        #[test]
        fn timeout_in_guest() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // Spawn a thread to terminate the instance after waiting for 100ms.
            let t = thread::Builder::new()
                .name("killswitch".to_owned())
                .spawn(move || {
                    thread::sleep(Duration::from_millis(100));
                    assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Signalled));
                })
                .expect("can spawn a thread");

            // Begin running the instance, which should be terminated remotely by the KillSwitch.
            match inst.run("infinite_loop", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {
                    // this is what we want to see
                }
                res => panic!("unexpected result: {:?}", res),
            }
            t.join().unwrap();

            // Another attempt to terminate the instance should fail.
            assert_eq!(
                inst.kill_switch().terminate(),
                Err(KillError::NotTerminable)
            );

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        #[test]
        fn timeout_before_guest_runs() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // If terminated before running, the guest will be cancelled.
            assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Cancelled));

            // Another attempt to terminate the instance should fail.
            assert_eq!(
                inst.kill_switch().terminate(),
                Err(KillError::NotTerminable)
            );

            match inst.run("onetwothree", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        /// FIXME: This needs a subtle change.
        #[test]
        fn timeout_after_guest_runs() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // The killswitch should fail if the instance has already finished running.
            match inst.run("do_nothing", &[]) {
                Ok(_) => {}
                res => panic!("unexpected result: {:?}", res),
            }
            assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Cancelled)); // FIXME -> Invalid

            // If terminated after running, the guest should not run again.
            match inst.run("onetwothree", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        #[test]
        fn timeout_after_guest_fault() {
            let module = test_module_c("timeout", "fault.c").expect("build and load module");
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // Run the faulting guest.
            match inst.run("main", &[0u32.into(), 0u32.into()]) {
                Err(Error::RuntimeFault(details)) => {
                    assert_eq!(details.trapcode, Some(TrapCode::HeapOutOfBounds));
                }
                res => panic!("unexpected result: {:?}", res),
            }

            // An instance that has faulted is not terminable.
            assert_eq!(kill_switch.terminate(), Err(KillError::NotTerminable));

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        #[test]
        fn timeout_in_hostcall() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // Spawn a thread to terminate the instance after waiting for 100ms.
            thread::Builder::new()
                .name("killswitch".to_owned())
                .spawn(move || {
                    thread::sleep(Duration::from_millis(100));
                    assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Pending));
                })
                .expect("can spawn a thread");

            // Begin running the instance, which should be terminated remotely by the KillSwitch
            // while inside a hostcall. See `slow_hostcall` above for more information.
            match inst.run("run_slow_hostcall", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Another attempt to terminate the instance should fail.
            assert_eq!(
                inst.kill_switch().terminate(),
                Err(KillError::NotTerminable)
            );

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        #[test]
        fn timeout_while_yielded() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // Start the instance, running a function that will yield.
            match inst.run("run_yielding_hostcall", &[]) {
                Ok(RunResult::Yielded(EmptyYieldVal)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // A yielded instance can only be scheduled for termination.
            assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Pending));

            // A second attempt to terminate a yielded instance will fail.
            assert_eq!(
                inst.kill_switch().terminate(),
                Err(KillError::NotTerminable)
            );

            // Once resumed, the terminated instance will be terminated.
            match inst.resume() {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        /// This test ensures that we see a more informative kill error than `NotTerminable` when
        /// attempting to terminate an instance that has been reset since issuing a kill switch.
        #[test]
        fn timeout_after_guest_reset() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();
            inst.reset().expect("instance resets");
            assert_eq!(kill_switch.terminate(), Err(KillError::Invalid));
            run_onetwothree(&mut inst);
        }

        /// This test ensures that we see an `Invalid` kill error if we are attempting to terminate
        /// an instance that has since been dropped.
        #[test]
        fn timeout_after_guest_drop() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();
            std::mem::drop(inst);
            assert_eq!(kill_switch.terminate(), Err(KillError::Invalid));
        }

        #[test]
        fn double_timeout() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");

            // Spawn a thread to terminate the instance after waiting for 100ms.
            let kill_switch = inst.kill_switch();
            let helper_1 = thread::Builder::new()
                .name("helper-1".to_owned())
                .spawn(move || {
                    thread::sleep(Duration::from_millis(100));
                    assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Signalled));
                })
                .expect("can spawn a thread");

            // Spawn a thread to terminate the instance after waiting for 200ms.
            let second_kill_switch = inst.kill_switch();
            let helper_2 = thread::Builder::new()
                .name("helper-2".to_owned())
                .spawn(move || {
                    thread::sleep(Duration::from_millis(200));
                    assert_eq!(
                        second_kill_switch.terminate(),
                        Err(KillError::NotTerminable)
                    );
                })
                .expect("can spawn a thread");

            // Start the instance, which should return an error having been remotely terminated.
            match inst.run("infinite_loop", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Explicitly check that each helper thread's assertions succeeded.
            helper_1.join().expect("helper_1 did not panic");
            helper_2.join().expect("helper_2 did not panic");

            // Check that we can reset the instance and run a function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }
    };
}
<commit_msg>lucet-runtime: fix comment phrasing<commit_after>//! Termination tests.
//!
//! This macro tests that instances within some kind of memory region can be terminated properly
//! using a remote kill switch. See
//! [`KillSwitch::terminate`](struct.KillSwitch.html#method.terminate) for more information.
#[macro_export]
macro_rules! timeout_tests {
    ( $TestRegion:path ) => {
        use lucet_runtime::vmctx::{lucet_vmctx, Vmctx};
        use lucet_runtime::{
            lucet_hostcall, lucet_hostcall_terminate, DlModule, Error, FaultDetails, Instance,
            KillError, KillSuccess, Limits, Module, Region, RunResult, SignalBehavior,
            TerminationDetails, TrapCode, YieldedVal,
        };
        use nix::sys::mman::{mmap, MapFlags, ProtFlags};
        use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal};
        use nix::sys::wait::{waitpid, WaitStatus};
        use nix::unistd::{fork, ForkResult};
        use std::ptr;
        use std::sync::{Arc, Mutex};
        use std::thread;
        use std::time::Duration;
        use $TestRegion as TestRegion;
        use $crate::build::test_module_c;
        use $crate::helpers::{FunctionPointer, MockExportBuilder, MockModuleBuilder};

        /// Return a mock module so that we can test termination behavior.
        ///
        /// See `lucet_runtime_internals::module::mock::MockModuleBuilder` for more information.
        pub fn mock_timeout_module() -> Arc<dyn Module> {
            extern "C" fn onetwothree(_vmctx: *mut lucet_vmctx) -> std::os::raw::c_int {
                123
            }

            extern "C" fn infinite_loop(_vmctx: *mut lucet_vmctx) -> () {
                loop {}
            }

            extern "C" fn do_nothing(_vmctx: *mut lucet_vmctx) -> () {}

            extern "C" fn run_slow_hostcall(vmctx: *mut lucet_vmctx) -> bool {
                extern "C" {
                    fn slow_hostcall(vmctx: *mut lucet_vmctx) -> bool;
                }
                unsafe { slow_hostcall(vmctx) }
            }

            extern "C" fn run_yielding_hostcall(vmctx: *mut lucet_vmctx) -> () {
                extern "C" {
                    fn yielding_hostcall(vmctx: *mut lucet_vmctx) -> ();
                }
                unsafe { yielding_hostcall(vmctx) }
            }

            MockModuleBuilder::new()
                .with_export_func(MockExportBuilder::new(
                    "infinite_loop",
                    FunctionPointer::from_usize(infinite_loop as usize),
                ))
                .with_export_func(MockExportBuilder::new(
                    "do_nothing",
                    FunctionPointer::from_usize(do_nothing as usize),
                ))
                .with_export_func(MockExportBuilder::new(
                    "onetwothree",
                    FunctionPointer::from_usize(onetwothree as usize),
                ))
                .with_export_func(MockExportBuilder::new(
                    "run_slow_hostcall",
                    FunctionPointer::from_usize(run_slow_hostcall as usize),
                ))
                .with_export_func(MockExportBuilder::new(
                    "run_yielding_hostcall",
                    FunctionPointer::from_usize(run_yielding_hostcall as usize),
                ))
                .build()
        }

        /// This test hostcall will wait for 200 milliseconds before returning `true`.
        /// This is used to make a window of time so we can timeout inside of a hostcall.
        #[lucet_hostcall]
        #[no_mangle]
        pub fn slow_hostcall(vmctx: &mut Vmctx) -> bool {
            thread::sleep(Duration::from_millis(200));
            true
        }

        /// This test hostcall will immediately yield. This is used to test termination of a
        /// yielded instance.
        #[lucet_hostcall]
        #[no_mangle]
        pub fn yielding_hostcall(vmctx: &mut Vmctx) {
            vmctx.yield_();
        }

        /// A convenience wrapper around running our mock timeout module's `onetwothree` function,
        /// and asserting that it returned the expected result.
        fn run_onetwothree(inst: &mut Instance) {
            let retval = inst
                .run("onetwothree", &[])
                .expect("instance runs")
                .unwrap_returned();
            assert_eq!(libc::c_int::from(retval), 123);
        }

        #[test]
        fn timeout_in_guest() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // Spawn a thread to terminate the instance after waiting for 100ms.
            let t = thread::Builder::new()
                .name("killswitch".to_owned())
                .spawn(move || {
                    thread::sleep(Duration::from_millis(100));
                    assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Signalled));
                })
                .expect("can spawn a thread");

            // Begin running the instance, which will be terminated remotely by the KillSwitch.
            match inst.run("infinite_loop", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {
                    // this is what we want to see
                }
                res => panic!("unexpected result: {:?}", res),
            }
            t.join().unwrap();

            // Another attempt to terminate the instance will fail.
            assert_eq!(
                inst.kill_switch().terminate(),
                Err(KillError::NotTerminable)
            );

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        #[test]
        fn timeout_before_guest_runs() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // If terminated before running, the guest will be cancelled.
            assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Cancelled));

            // Another attempt to terminate the instance will fail.
            assert_eq!(
                inst.kill_switch().terminate(),
                Err(KillError::NotTerminable)
            );

            match inst.run("onetwothree", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        /// FIXME: This needs a subtle change.
        #[test]
        fn timeout_after_guest_runs() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // The killswitch will fail if the instance has already finished running.
            match inst.run("do_nothing", &[]) {
                Ok(_) => {}
                res => panic!("unexpected result: {:?}", res),
            }
            assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Cancelled)); // FIXME -> Invalid

            // If terminated after running, the guest will not run again.
            match inst.run("onetwothree", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        #[test]
        fn timeout_after_guest_fault() {
            let module = test_module_c("timeout", "fault.c").expect("build and load module");
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // Run the faulting guest.
            match inst.run("main", &[0u32.into(), 0u32.into()]) {
                Err(Error::RuntimeFault(details)) => {
                    assert_eq!(details.trapcode, Some(TrapCode::HeapOutOfBounds));
                }
                res => panic!("unexpected result: {:?}", res),
            }

            // An instance that has faulted is not terminable.
            assert_eq!(kill_switch.terminate(), Err(KillError::NotTerminable));

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        #[test]
        fn timeout_in_hostcall() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // Spawn a thread to terminate the instance after waiting for 100ms.
            thread::Builder::new()
                .name("killswitch".to_owned())
                .spawn(move || {
                    thread::sleep(Duration::from_millis(100));
                    assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Pending));
                })
                .expect("can spawn a thread");

            // Begin running the instance, which will be terminated remotely by the KillSwitch
            // while inside a hostcall. See `slow_hostcall` above for more information.
            match inst.run("run_slow_hostcall", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Another attempt to terminate the instance will fail.
            assert_eq!(
                inst.kill_switch().terminate(),
                Err(KillError::NotTerminable)
            );

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        #[test]
        fn timeout_while_yielded() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();

            // Start the instance, running a function that will yield.
            match inst.run("run_yielding_hostcall", &[]) {
                Ok(RunResult::Yielded(EmptyYieldVal)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // A yielded instance can only be scheduled for termination.
            assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Pending));

            // A second attempt to terminate a yielded instance will fail.
            assert_eq!(
                inst.kill_switch().terminate(),
                Err(KillError::NotTerminable)
            );

            // Once resumed, the terminated instance will be terminated.
            match inst.resume() {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Check that we can reset the instance and run a normal function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }

        /// This test ensures that we see a more informative kill error than `NotTerminable` when
        /// attempting to terminate an instance that has been reset since issuing a kill switch.
        #[test]
        fn timeout_after_guest_reset() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();
            inst.reset().expect("instance resets");
            assert_eq!(kill_switch.terminate(), Err(KillError::Invalid));
            run_onetwothree(&mut inst);
        }

        /// This test ensures that we see an `Invalid` kill error if we are attempting to terminate
        /// an instance that has since been dropped.
        #[test]
        fn timeout_after_guest_drop() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");
            let kill_switch = inst.kill_switch();
            std::mem::drop(inst);
            assert_eq!(kill_switch.terminate(), Err(KillError::Invalid));
        }

        #[test]
        fn double_timeout() {
            let module = mock_timeout_module();
            let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");

            // Spawn a thread to terminate the instance after waiting for 100ms.
            let kill_switch = inst.kill_switch();
            let helper_1 = thread::Builder::new()
                .name("helper-1".to_owned())
                .spawn(move || {
                    thread::sleep(Duration::from_millis(100));
                    assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Signalled));
                })
                .expect("can spawn a thread");

            // Spawn a thread to terminate the instance after waiting for 200ms.
            let second_kill_switch = inst.kill_switch();
            let helper_2 = thread::Builder::new()
                .name("helper-2".to_owned())
                .spawn(move || {
                    thread::sleep(Duration::from_millis(200));
                    assert_eq!(
                        second_kill_switch.terminate(),
                        Err(KillError::NotTerminable)
                    );
                })
                .expect("can spawn a thread");

            // Start the instance, which will return an error having been remotely terminated.
            match inst.run("infinite_loop", &[]) {
                Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {}
                res => panic!("unexpected result: {:?}", res),
            }

            // Explicitly check that each helper thread's assertions succeeded.
            helper_1.join().expect("helper_1 did not panic");
            helper_2.join().expect("helper_2 did not panic");

            // Check that we can reset the instance and run a function.
            inst.reset().expect("instance resets");
            run_onetwothree(&mut inst);
        }
    };
}
<|endoftext|>


<commit_before>use super::*;
use std::path::Path;

cpp_class!(pub unsafe struct SBPlatform as "SBPlatform");

unsafe impl Send for SBPlatform {}

impl SBPlatform {
    pub fn clear(&self) {
        cpp!(unsafe [self as "SBPlatform*"] {
            return self->Clear();
        })
    }
    pub fn name(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetName();
        });
        unsafe { get_str(ptr) }
    }
    pub fn is_connected(&self) -> bool {
        cpp!(unsafe [self as "SBPlatform*"] -> bool as "bool" {
            return self->IsConnected();
        })
    }
    pub fn triple(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetTriple();
        });
        unsafe { get_str(ptr) }
    }
    pub fn hostname(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetHostname();
        });
        unsafe { get_str(ptr) }
    }
    pub fn os_build(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetOSBuild();
        });
        unsafe { get_str(ptr) }
    }
    pub fn os_description(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetOSDescription();
        });
        unsafe { get_str(ptr) }
    }
    pub fn get_file_permissions(&self, path: &Path) -> u32 {
        with_cstr(path.to_str().unwrap(), |path| {
            cpp!(unsafe [self as "SBPlatform*", path as "const char*"] -> u32 as "uint32_t" {
                return self->GetFilePermissions(path);
            })
        })
    }
    pub fn launch(&self, launch_info: &SBLaunchInfo) -> Result<(), SBError> {
        cpp!(unsafe [self as "SBPlatform*", launch_info as "SBLaunchInfo*"] -> SBError as "SBError" {
            return self->Launch(*launch_info);
        })
        .into_result()
    }
    pub fn kill(&self, pid: ProcessID) -> Result<(), SBError> {
        cpp!(unsafe [self as "SBPlatform*", pid as "lldb::pid_t"] -> SBError as "SBError" {
            return self->Kill(pid);
        })
        .into_result()
    }
}

impl IsValid for SBPlatform {
    fn is_valid(&self) -> bool {
        cpp!(unsafe [self as "SBPlatform*"] -> bool as "bool" {
            return self->IsValid();
        })
    }
}
<commit_msg>More SBPlatform bindings.<commit_after>use super::*;
use std::path::Path;

cpp_class!(pub unsafe struct SBPlatform as "SBPlatform");

unsafe impl Send for SBPlatform {}

impl SBPlatform {
    pub fn clear(&self) {
        cpp!(unsafe [self as "SBPlatform*"] {
            return self->Clear();
        })
    }
    pub fn name(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetName();
        });
        unsafe { get_str(ptr) }
    }
    pub fn connect_remote(&self, connect_options: &SBPlatformConnectOptions) -> SBError {
        cpp!(unsafe  [self as "SBPlatform*", connect_options as "SBPlatformConnectOptions*"] -> SBError as "SBError" {
            return self->ConnectRemote(*connect_options);
        })
    }
    pub fn disconnect_remote(&self) {
        cpp!(unsafe [self as "SBPlatform*"] {
            self->DisconnectRemote();
        })
    }
    pub fn is_connected(&self) -> bool {
        cpp!(unsafe [self as "SBPlatform*"] -> bool as "bool" {
            return self->IsConnected();
        })
    }
    pub fn triple(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetTriple();
        });
        unsafe { get_str(ptr) }
    }
    pub fn hostname(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetHostname();
        });
        unsafe { get_str(ptr) }
    }
    pub fn os_build(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetOSBuild();
        });
        unsafe { get_str(ptr) }
    }
    pub fn os_description(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatform*"] -> *const c_char as "const char*" {
            return self->GetOSDescription();
        });
        unsafe { get_str(ptr) }
    }
    pub fn get_file_permissions(&self, path: &Path) -> u32 {
        with_cstr(path.to_str().unwrap(), |path| {
            cpp!(unsafe [self as "SBPlatform*", path as "const char*"] -> u32 as "uint32_t" {
                return self->GetFilePermissions(path);
            })
        })
    }
    pub fn launch(&self, launch_info: &SBLaunchInfo) -> Result<(), SBError> {
        cpp!(unsafe [self as "SBPlatform*", launch_info as "SBLaunchInfo*"] -> SBError as "SBError" {
            return self->Launch(*launch_info);
        })
        .into_result()
    }
    pub fn kill(&self, pid: ProcessID) -> Result<(), SBError> {
        cpp!(unsafe [self as "SBPlatform*", pid as "lldb::pid_t"] -> SBError as "SBError" {
            return self->Kill(pid);
        })
        .into_result()
    }
}

impl IsValid for SBPlatform {
    fn is_valid(&self) -> bool {
        cpp!(unsafe [self as "SBPlatform*"] -> bool as "bool" {
            return self->IsValid();
        })
    }
}

cpp_class!(pub unsafe struct SBPlatformConnectOptions as "SBPlatformConnectOptions");

unsafe impl Send for SBPlatformConnectOptions {}

impl SBPlatformConnectOptions {
    pub fn new(url: &str) -> Self {
        with_cstr(url, |url| {
            cpp!(unsafe [url as "const char*"] -> SBPlatformConnectOptions as "SBPlatformConnectOptions" {
                return SBPlatformConnectOptions(url);
            })
        })
    }
    pub fn url(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatformConnectOptions*"] -> *const c_char as "const char*" {
            return self->GetURL();
        });
        unsafe { get_str(ptr) }
    }
    pub fn set_url(&self, url: &str) {
        with_cstr(url, |url| {
            cpp!(unsafe [self as "SBPlatformConnectOptions*", url as "const char*"] {
                self->SetURL(url);
            });
        })
    }
    pub fn rsync_enabled(&self) -> bool {
        cpp!(unsafe [self as "SBPlatformConnectOptions*"] -> bool as "bool" {
            return self->GetRsyncEnabled();
        })
    }
    pub fn enable_rsync(&self, options: &str, remote_path_prefix: &str, omit_remote_hostname: bool) {
        with_cstr(options, |options| {
            with_cstr(remote_path_prefix, |remote_path_prefix| {
                cpp!(unsafe [self as "SBPlatformConnectOptions*", options as "const char *",
                            remote_path_prefix as "const char *", omit_remote_hostname as "bool"] {
                    self->EnableRsync(options, remote_path_prefix, omit_remote_hostname);
                });
            })
        })
    }
    pub fn disable_rsync(&self) {
        cpp!(unsafe [self as "SBPlatformConnectOptions*"]  {
            return self->DisableRsync();
        })
    }
    pub fn local_cache_directory(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatformConnectOptions*"] -> *const c_char as "const char*" {
            return self->GetLocalCacheDirectory();
        });
        unsafe { get_str(ptr) }
    }
    pub fn set_local_cache_directory(&self, path: &str) {
        with_cstr(path, |path| {
            cpp!(unsafe [self as "SBPlatformConnectOptions*", path as "const char*"] {
                self->SetLocalCacheDirectory(path);
            });
        })
    }
}

cpp_class!(pub unsafe struct SBPlatformShellCommand as "SBPlatformShellCommand");

unsafe impl Send for SBPlatformShellCommand {}

impl SBPlatformShellCommand {
    pub fn new(command: &str) -> Self {
        with_cstr(command, |command| {
            cpp!(unsafe [command as "const char*"] -> SBPlatformShellCommand as "SBPlatformShellCommand" {
                return SBPlatformShellCommand(command);
            })
        })
    }
    pub fn clear(&self) {
        cpp!(unsafe [self as "SBPlatformShellCommand*"] {
            return self->Clear();
        })
    }
    pub fn command(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatformShellCommand*"] -> *const c_char as "const char*" {
            return self->GetCommand();
        });
        unsafe { get_str(ptr) }
    }
    pub fn set_command(&self, command: &str) {
        with_cstr(command, |command| {
            cpp!(unsafe [self as "SBPlatformShellCommand*", command as "const char*"] {
                self->SetCommand(command);
            });
        })
    }
    pub fn working_directory(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatformShellCommand*"] -> *const c_char as "const char*" {
            return self->GetWorkingDirectory();
        });
        unsafe { get_str(ptr) }
    }
    pub fn set_working_directory(&self, path: &str) {
        with_cstr(path, |path| {
            cpp!(unsafe [self as "SBPlatformShellCommand*", path as "const char*"] {
                self->SetWorkingDirectory(path);
            });
        })
    }
    pub fn timeout_seconds(&self) -> u32 {
        cpp!(unsafe [self as "SBPlatformShellCommand*"] -> u32 as "uint32_t" {
            return self->GetTimeoutSeconds();
        })
    }
    pub fn set_timeout_seconds(&self, sec: u32) {
        cpp!(unsafe [self as "SBPlatformShellCommand*", sec as "uint32_t"] {
            self->SetTimeoutSeconds(sec);
        });
    }
    pub fn signal(&self) -> i32 {
        cpp!(unsafe [self as "SBPlatformShellCommand*"] -> c_int as "int" {
            return self->GetSignal();
        }) as i32
    }
    pub fn status(&self) -> i32 {
        cpp!(unsafe [self as "SBPlatformShellCommand*"] -> c_int as "int" {
            return self->GetStatus();
        }) as i32
    }
    pub fn output(&self) -> &str {
        let ptr = cpp!(unsafe [self as "SBPlatformShellCommand*"] -> *const c_char as "const char*" {
            return self->GetOutput();
        });
        unsafe { get_str(ptr) }
    }
}
<|endoftext|>


<commit_before>// 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.

use std::rc::Rc;
use super::constants::*;
use super::nodes::*;

/// Store a command tree while populating it. This is used
/// to construct a [`RootNode`] to be used with the [`Parser`].
///
/// The lifetime parameter `'a` refers to the lifetime
/// of the strings used for [command] and [parameter] names and
/// help text.
///
/// [command]: struct.Command.html
/// [parameter]: struct.Parameter.html
/// [`Parser`]: struct.Parser.html
/// [`RootNode`]: struct.RootNode.html
pub struct CommandTree<'a> {
    commands: Vec<Command<'a>>,
}

impl<'a> Default for CommandTree<'a> {
    fn default() -> Self {
        CommandTree { commands: vec![] }
    }
}

impl<'a> CommandTree<'a> {
    /// Create a new `CommandTree`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Add a `Command` to the `CommandTree`.
    pub fn command(&mut self, command: Command<'a>) {
        self.commands.push(command);
    }

    /// Construct the `CommandTree` and produce a `RootNode`.
    pub fn finalize(&self) -> Rc<Node> {
        let mut successors: Vec<Rc<Node>> = vec![];
        for c in &self.commands {
            successors.push(Rc::new(Node::Command(self.build_command(c))));
        }
        Rc::new(Node::Root(RootNode::new(successors)))
    }

    fn build_command(&self, command: &Command) -> CommandNode {
        let mut parameters: Vec<Rc<Node>> = vec![];
        let mut successors: Vec<Rc<Node>> = vec![];
        for parameter in &command.parameters {
            match parameter.kind {
                ParameterKind::Flag => {
                    self.build_flag_parameter(parameter, &mut parameters, &mut successors);
                }
                ParameterKind::Named => {
                    self.build_named_parameter(parameter, &mut parameters, &mut successors);
                }
                ParameterKind::Simple => {
                    self.build_simple_parameter(parameter, &mut parameters, &mut successors);
                }
            };
        }
        // We'll want to find the right node for the wrapped_root
        // and pass it along here.
        CommandNode::new(command.name,
                         command.help_text,
                         command.hidden,
                         command.priority,
                         successors,
                         None,
                         parameters)
    }

    fn build_flag_parameter(&self,
                            parameter: &Parameter,
                            parameters: &mut Vec<Rc<Node>>,
                            successors: &mut Vec<Rc<Node>>) {
        let p = ParameterNode::new(parameter.name,
                                   parameter.help_text,
                                   parameter.hidden,
                                   parameter.priority.unwrap_or(PRIORITY_DEFAULT),
                                   vec![],
                                   parameter.repeatable,
                                   None,
                                   parameter.kind,
                                   parameter.required);
        let p = Rc::new(Node::Parameter(p));
        parameters.push(p.clone());
        successors.push(p);
    }

    fn build_named_parameter(&self,
                             parameter: &Parameter,
                             parameters: &mut Vec<Rc<Node>>,
                             successors: &mut Vec<Rc<Node>>) {
        let p = ParameterNode::new(parameter.name,
                                   parameter.help_text,
                                   parameter.hidden,
                                   parameter.priority
                                            .unwrap_or(PRIORITY_PARAMETER),
                                   vec![],
                                   parameter.repeatable,
                                   None,
                                   parameter.kind,
                                   parameter.required);
        let p = Rc::new(Node::Parameter(p));
        parameters.push(p.clone());
        let n = ParameterNameNode::new(parameter.name,
                                       parameter.hidden,
                                       PRIORITY_DEFAULT,
                                       vec![p.clone()],
                                       parameter.repeatable,
                                       Some(p.clone()),
                                       p.clone());
        successors.push(Rc::new(Node::ParameterName(n)));
        for alias in &parameter.aliases {
            let a = ParameterNameNode::new(alias,
                                           parameter.hidden,
                                           PRIORITY_DEFAULT,
                                           vec![p.clone()],
                                           parameter.repeatable,
                                           Some(p.clone()),
                                           p.clone());
            successors.push(Rc::new(Node::ParameterName(a)));
        }
    }

    fn build_simple_parameter(&self,
                              parameter: &Parameter,
                              parameters: &mut Vec<Rc<Node>>,
                              successors: &mut Vec<Rc<Node>>) {
        let p = ParameterNode::new(parameter.name,
                                   parameter.help_text,
                                   parameter.hidden,
                                   parameter.priority.unwrap_or(PRIORITY_PARAMETER),
                                   vec![],
                                   parameter.repeatable,
                                   None,
                                   parameter.kind,
                                   parameter.required);
        let p = Rc::new(Node::Parameter(p));
        parameters.push(p.clone());
        successors.push(p.clone());
    }
}

/// Description of a command to be added to the [`CommandTree`].
///
/// The lifetime parameter `'a` refers to the lifetime
/// of the strings used for command names and help text.
///
/// [`CommandTree`]: struct.CommandTree.html
pub struct Command<'a> {
    hidden: bool,
    priority: i32,
    name: &'a str,
    help_text: Option<&'a str>,
    parameters: Vec<Parameter<'a>>,
    wrapped_root: Option<String>,
}

impl<'a> Command<'a> {
    /// Construct a default (blank) command with the given `name`.
    pub fn new(name: &'a str) -> Self {
        Command {
            hidden: false,
            priority: PRIORITY_DEFAULT,
            name: name,
            help_text: None,
            parameters: vec![],
            wrapped_root: None,
        }
    }

    /// Mark the command as hidden. Hidden commands will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(mut self, hidden: bool) -> Self {
        self.hidden = hidden;
        self
    }

    /// Give the command a priority. This is used when sorting
    /// out conflicts during matching and completion.
    pub fn priority(mut self, priority: i32) -> Self {
        self.priority = priority;
        self
    }

    /// Supply help text for the command.
    pub fn help(mut self, help_text: &'a str) -> Self {
        self.help_text = Some(help_text);
        self
    }

    /// Add a [`Parameter`] to the command.
    ///
    /// [`Parameter`]: struct.Parameter.html
    pub fn parameter(mut self, parameter: Parameter<'a>) -> Self {
        self.parameters.push(parameter);
        self
    }

    /// The `wrapped_root` signifies the path to the command that should
    /// be wrapped by this command. This is used for the `help` command.
    ///
    /// [`CommandNode`]: struct.CommandNode.html
    pub fn wraps(mut self, wrapped_root: String) -> Self {
        self.wrapped_root = Some(wrapped_root);
        self
    }
}

/// Description of a parameter to be added to the [`Command`].
///
/// The lifetime parameter `'a` refers to the lifetime
/// of the strings used for parameter names, aliases and
/// help text.
///
/// [`Command`]: struct.Command.html
pub struct Parameter<'a> {
    hidden: bool,
    priority: Option<i32>,
    name: &'a str,
    repeatable: bool,
    aliases: Vec<&'a str>,
    help_text: Option<&'a str>,
    kind: ParameterKind,
    required: bool,
}

impl<'a> Parameter<'a> {
    /// Construct a default (blank) parameter with the given `name`.
    pub fn new(name: &'a str) -> Self {
        Parameter {
            hidden: false,
            priority: None,
            name: name,
            repeatable: false,
            aliases: vec![],
            help_text: None,
            kind: ParameterKind::Simple,
            required: false,
        }
    }

    /// Mark the parameter as hidden. Hidden parameters will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(mut self, hidden: bool) -> Self {
        self.hidden = hidden;
        self
    }

    /// Give the parameter a priority. This is used when sorting
    /// out conflicts during matching and completion.
    ///
    /// The `priority` of a `Parameter` defaults to `PRIORITY_PARAMETER`
    /// except for when the `kind` is `ParameterKind::Flag` in which
    /// case, the default will be `PRIORITY_DEFAULT`.
    pub fn priority(mut self, priority: i32) -> Self {
        self.priority = Some(priority);
        self
    }

    /// Establish whether or not this parameter is repeatable.
    /// Repeated parameters produce a vector of values and can
    /// be given multiple times within a single command invocation.
    pub fn repeatable(mut self, repeatable: bool) -> Self {
        self.repeatable = repeatable;
        self
    }

    /// Add an alias that this parameter can use.
    ///
    /// Aliases are currently only valid for parameters of `kind`
    /// `ParameterKind::Named`.
    pub fn alias(mut self, alias: &'a str) -> Self {
        self.aliases.push(alias);
        self
    }

    /// Supply the help text for the parameter.
    pub fn help(mut self, help_text: &'a str) -> Self {
        self.help_text = Some(help_text);
        self
    }

    /// Establish whether or not this parameter is required.
    pub fn required(mut self, required: bool) -> Self {
        self.required = required;
        self
    }

    /// Set which type of [`ParameterNode`] is supposed to be created
    /// to represent this parameter.
    ///
    /// [`ParameterNode`]: trait.ParameterNode.html
    pub fn kind(mut self, kind: ParameterKind) -> Self {
        self.kind = kind;
        self
    }
}
<commit_msg>Note that modifying priority isn't often needed.<commit_after>// 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.

use std::rc::Rc;
use super::constants::*;
use super::nodes::*;

/// Store a command tree while populating it. This is used
/// to construct a [`RootNode`] to be used with the [`Parser`].
///
/// The lifetime parameter `'a` refers to the lifetime
/// of the strings used for [command] and [parameter] names and
/// help text.
///
/// [command]: struct.Command.html
/// [parameter]: struct.Parameter.html
/// [`Parser`]: struct.Parser.html
/// [`RootNode`]: struct.RootNode.html
pub struct CommandTree<'a> {
    commands: Vec<Command<'a>>,
}

impl<'a> Default for CommandTree<'a> {
    fn default() -> Self {
        CommandTree { commands: vec![] }
    }
}

impl<'a> CommandTree<'a> {
    /// Create a new `CommandTree`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Add a `Command` to the `CommandTree`.
    pub fn command(&mut self, command: Command<'a>) {
        self.commands.push(command);
    }

    /// Construct the `CommandTree` and produce a `RootNode`.
    pub fn finalize(&self) -> Rc<Node> {
        let mut successors: Vec<Rc<Node>> = vec![];
        for c in &self.commands {
            successors.push(Rc::new(Node::Command(self.build_command(c))));
        }
        Rc::new(Node::Root(RootNode::new(successors)))
    }

    fn build_command(&self, command: &Command) -> CommandNode {
        let mut parameters: Vec<Rc<Node>> = vec![];
        let mut successors: Vec<Rc<Node>> = vec![];
        for parameter in &command.parameters {
            match parameter.kind {
                ParameterKind::Flag => {
                    self.build_flag_parameter(parameter, &mut parameters, &mut successors);
                }
                ParameterKind::Named => {
                    self.build_named_parameter(parameter, &mut parameters, &mut successors);
                }
                ParameterKind::Simple => {
                    self.build_simple_parameter(parameter, &mut parameters, &mut successors);
                }
            };
        }
        // We'll want to find the right node for the wrapped_root
        // and pass it along here.
        CommandNode::new(command.name,
                         command.help_text,
                         command.hidden,
                         command.priority,
                         successors,
                         None,
                         parameters)
    }

    fn build_flag_parameter(&self,
                            parameter: &Parameter,
                            parameters: &mut Vec<Rc<Node>>,
                            successors: &mut Vec<Rc<Node>>) {
        let p = ParameterNode::new(parameter.name,
                                   parameter.help_text,
                                   parameter.hidden,
                                   parameter.priority.unwrap_or(PRIORITY_DEFAULT),
                                   vec![],
                                   parameter.repeatable,
                                   None,
                                   parameter.kind,
                                   parameter.required);
        let p = Rc::new(Node::Parameter(p));
        parameters.push(p.clone());
        successors.push(p);
    }

    fn build_named_parameter(&self,
                             parameter: &Parameter,
                             parameters: &mut Vec<Rc<Node>>,
                             successors: &mut Vec<Rc<Node>>) {
        let p = ParameterNode::new(parameter.name,
                                   parameter.help_text,
                                   parameter.hidden,
                                   parameter.priority
                                            .unwrap_or(PRIORITY_PARAMETER),
                                   vec![],
                                   parameter.repeatable,
                                   None,
                                   parameter.kind,
                                   parameter.required);
        let p = Rc::new(Node::Parameter(p));
        parameters.push(p.clone());
        let n = ParameterNameNode::new(parameter.name,
                                       parameter.hidden,
                                       PRIORITY_DEFAULT,
                                       vec![p.clone()],
                                       parameter.repeatable,
                                       Some(p.clone()),
                                       p.clone());
        successors.push(Rc::new(Node::ParameterName(n)));
        for alias in &parameter.aliases {
            let a = ParameterNameNode::new(alias,
                                           parameter.hidden,
                                           PRIORITY_DEFAULT,
                                           vec![p.clone()],
                                           parameter.repeatable,
                                           Some(p.clone()),
                                           p.clone());
            successors.push(Rc::new(Node::ParameterName(a)));
        }
    }

    fn build_simple_parameter(&self,
                              parameter: &Parameter,
                              parameters: &mut Vec<Rc<Node>>,
                              successors: &mut Vec<Rc<Node>>) {
        let p = ParameterNode::new(parameter.name,
                                   parameter.help_text,
                                   parameter.hidden,
                                   parameter.priority.unwrap_or(PRIORITY_PARAMETER),
                                   vec![],
                                   parameter.repeatable,
                                   None,
                                   parameter.kind,
                                   parameter.required);
        let p = Rc::new(Node::Parameter(p));
        parameters.push(p.clone());
        successors.push(p.clone());
    }
}

/// Description of a command to be added to the [`CommandTree`].
///
/// The lifetime parameter `'a` refers to the lifetime
/// of the strings used for command names and help text.
///
/// [`CommandTree`]: struct.CommandTree.html
pub struct Command<'a> {
    hidden: bool,
    priority: i32,
    name: &'a str,
    help_text: Option<&'a str>,
    parameters: Vec<Parameter<'a>>,
    wrapped_root: Option<String>,
}

impl<'a> Command<'a> {
    /// Construct a default (blank) command with the given `name`.
    pub fn new(name: &'a str) -> Self {
        Command {
            hidden: false,
            priority: PRIORITY_DEFAULT,
            name: name,
            help_text: None,
            parameters: vec![],
            wrapped_root: None,
        }
    }

    /// Mark the command as hidden. Hidden commands will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(mut self, hidden: bool) -> Self {
        self.hidden = hidden;
        self
    }

    /// Give the command a priority. This is used when sorting
    /// out conflicts during matching and completion.
    ///
    /// This is not commonly needed.
    pub fn priority(mut self, priority: i32) -> Self {
        self.priority = priority;
        self
    }

    /// Supply help text for the command.
    pub fn help(mut self, help_text: &'a str) -> Self {
        self.help_text = Some(help_text);
        self
    }

    /// Add a [`Parameter`] to the command.
    ///
    /// [`Parameter`]: struct.Parameter.html
    pub fn parameter(mut self, parameter: Parameter<'a>) -> Self {
        self.parameters.push(parameter);
        self
    }

    /// The `wrapped_root` signifies the path to the command that should
    /// be wrapped by this command. This is used for the `help` command.
    ///
    /// [`CommandNode`]: struct.CommandNode.html
    pub fn wraps(mut self, wrapped_root: String) -> Self {
        self.wrapped_root = Some(wrapped_root);
        self
    }
}

/// Description of a parameter to be added to the [`Command`].
///
/// The lifetime parameter `'a` refers to the lifetime
/// of the strings used for parameter names, aliases and
/// help text.
///
/// [`Command`]: struct.Command.html
pub struct Parameter<'a> {
    hidden: bool,
    priority: Option<i32>,
    name: &'a str,
    repeatable: bool,
    aliases: Vec<&'a str>,
    help_text: Option<&'a str>,
    kind: ParameterKind,
    required: bool,
}

impl<'a> Parameter<'a> {
    /// Construct a default (blank) parameter with the given `name`.
    pub fn new(name: &'a str) -> Self {
        Parameter {
            hidden: false,
            priority: None,
            name: name,
            repeatable: false,
            aliases: vec![],
            help_text: None,
            kind: ParameterKind::Simple,
            required: false,
        }
    }

    /// Mark the parameter as hidden. Hidden parameters will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(mut self, hidden: bool) -> Self {
        self.hidden = hidden;
        self
    }

    /// Give the parameter a priority. This is used when sorting
    /// out conflicts during matching and completion.
    ///
    /// The `priority` of a `Parameter` defaults to `PRIORITY_PARAMETER`
    /// except for when the `kind` is `ParameterKind::Flag` in which
    /// case, the default will be `PRIORITY_DEFAULT`.
    ///
    /// This is not commonly needed.
    pub fn priority(mut self, priority: i32) -> Self {
        self.priority = Some(priority);
        self
    }

    /// Establish whether or not this parameter is repeatable.
    /// Repeated parameters produce a vector of values and can
    /// be given multiple times within a single command invocation.
    pub fn repeatable(mut self, repeatable: bool) -> Self {
        self.repeatable = repeatable;
        self
    }

    /// Add an alias that this parameter can use.
    ///
    /// Aliases are currently only valid for parameters of `kind`
    /// `ParameterKind::Named`.
    pub fn alias(mut self, alias: &'a str) -> Self {
        self.aliases.push(alias);
        self
    }

    /// Supply the help text for the parameter.
    pub fn help(mut self, help_text: &'a str) -> Self {
        self.help_text = Some(help_text);
        self
    }

    /// Establish whether or not this parameter is required.
    pub fn required(mut self, required: bool) -> Self {
        self.required = required;
        self
    }

    /// Set which type of [`ParameterNode`] is supposed to be created
    /// to represent this parameter.
    ///
    /// [`ParameterNode`]: trait.ParameterNode.html
    pub fn kind(mut self, kind: ParameterKind) -> Self {
        self.kind = kind;
        self
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use types::GLError;

pub struct Renderbuffer {
    gl_id: GLuint
}

impl Renderbuffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Renderbuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteRenderbuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_renderbuffer(&self) -> Renderbuffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenRenderbuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Renderbuffer {
                gl_id: id
            }
        }
    }
}

gl_enum! {
    pub gl_enum RenderbufferTarget {
        Renderbuffer as RENDERBUFFER = gl::RENDERBUFFER
    }
}

pub struct RenderbufferBinding<'a> {
    phantom: PhantomData<&'a mut Renderbuffer>
}

impl<'a> RenderbufferBinding<'a> {
    fn target(&self) -> GLenum {
        gl::RENDERBUFFER
    }
}

pub struct RenderbufferBinder;
impl RenderbufferBinder {
    pub fn bind<'a>(&'a mut self, renderbuffer: &mut Renderbuffer)
        -> RenderbufferBinding<'a>
    {
        let binding = RenderbufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindRenderbuffer(binding.target(), renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_RENDERBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<commit_msg>Change `RenderbufferBinding.target()` to return a `RenderbufferTarget`<commit_after>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use types::GLError;

pub struct Renderbuffer {
    gl_id: GLuint
}

impl Renderbuffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Renderbuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteRenderbuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_renderbuffer(&self) -> Renderbuffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenRenderbuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Renderbuffer {
                gl_id: id
            }
        }
    }
}

gl_enum! {
    pub gl_enum RenderbufferTarget {
        Renderbuffer as RENDERBUFFER = gl::RENDERBUFFER
    }
}

pub struct RenderbufferBinding<'a> {
    phantom: PhantomData<&'a mut Renderbuffer>
}

impl<'a> RenderbufferBinding<'a> {
    fn target(&self) -> RenderbufferTarget {
        RenderbufferTarget::Renderbuffer
    }
}

pub struct RenderbufferBinder;
impl RenderbufferBinder {
    pub fn bind<'a>(&'a mut self, renderbuffer: &mut Renderbuffer)
        -> RenderbufferBinding<'a>
    {
        let binding = RenderbufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindRenderbuffer(binding.target().gl_enum(),
                                 renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_RENDERBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<|endoftext|>


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

extern crate env_logger;
extern crate rusoto_core;
extern crate rusoto_secretsmanager;

use rusoto_guardduty::{ListSecretsRequest, SecretsManager, SecretsManagerClient};
use rusoto_core::Region;

#[test]
fn should_list_invitations() {
  let _ = env_logger::try_init();
  let client = SecretsManagerClient::simple(Region::UsWest2);
  let request = ListSecretsRequest {
    ..Default::default()
  };

  let result = client.list_secrets(&request).sync();
  println!("{:#?}", result);
  assert!(result.is_ok());
}
<commit_msg>secretsmanager not guardduty<commit_after>#![cfg(feature = "secretsmanager")]

extern crate env_logger;
extern crate rusoto_core;
extern crate rusoto_secretsmanager;

use rusoto_secretsmanager::{ListSecretsRequest, SecretsManager, SecretsManagerClient};
use rusoto_core::Region;

#[test]
fn should_list_invitations() {
  let _ = env_logger::try_init();
  let client = SecretsManagerClient::simple(Region::UsWest2);
  let request = ListSecretsRequest {
    ..Default::default()
  };

  let result = client.list_secrets(&request).sync();
  println!("{:#?}", result);
  assert!(result.is_ok());
}
<|endoftext|>