<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use command_line::command_line_init;
use interfaces::cef_app_t;
use types::{cef_main_args_t, cef_settings_t};
use window::init_window;

use libc::{c_char, c_int, c_void};
use util::opts;
use std::ffi;
use std::str;
use browser;
use std_url::Url;

const MAX_RENDERING_THREADS: usize = 128;

static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg";

static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
#[cfg(target_os="windows")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"5c7f3e50ff5265985d11dc1a466513e25748bedd\0";
#[cfg(target_os="macos")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"6813214accbf2ebfb6bdcf8d00654650b251bf3d\0";
#[cfg(target_os="linux")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e17fa17a6d\0";

#[no_mangle]
pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
                                 settings: *mut cef_settings_t,
                                 application: *mut cef_app_t,
                                 _windows_sandbox_info: *const c_void)
                                 -> c_int {
    if args.is_null() {
        return 0;
    }

    unsafe {
        command_line_init((*args).argc, (*args).argv);

        if !application.is_null() {
            (*application).get_browser_process_handler.map(|cb| {
                    let handler = cb(application);
                    if !handler.is_null() {
                        (*handler).on_context_initialized.map(|hcb| hcb(handler));
                    }
            });
        }
    }

    let rendering_threads = unsafe {
        if ((*settings).rendering_threads as usize) < 1 {
            1
        } else if (*settings).rendering_threads as usize > MAX_RENDERING_THREADS {
            MAX_RENDERING_THREADS
        } else {
            (*settings).rendering_threads as usize
        }
    };

    let mut temp_opts = opts::default_opts();
    temp_opts.paint_threads = rendering_threads;
    temp_opts.layout_threads = rendering_threads;
    temp_opts.headless = false;
    temp_opts.hard_fail = false;
    temp_opts.enable_text_antialiasing = true;
    temp_opts.resources_path = None;
    temp_opts.url = Url::parse(HOME_URL).unwrap();
    opts::set(temp_opts);

    init_window();

    return 1
}

#[no_mangle]
pub extern "C" fn cef_shutdown() {
}

#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
    // GWTODO: Support blocking message loop
    // again. Although, will it ever actually
    // be used or will everything use the
    // cef_do_message_loop_work function below
    // as our current miniservo apps do?
    unimplemented!()
}

#[no_mangle]
pub extern "C" fn cef_do_message_loop_work() {
    browser::update();
}

#[no_mangle]
pub extern "C" fn cef_quit_message_loop() {
}

#[no_mangle]
pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t,
                                      _app: *mut cef_app_t,
                                      _windows_sandbox_info: *mut c_void)
                                      -> c_int {
    -1
}

#[no_mangle]
pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char {
    if entry == 0 {
        &CEF_API_HASH_PLATFORM[0] as *const u8 as *const c_char
    } else {
        &CEF_API_HASH_UNIVERSAL[0] as *const u8 as *const c_char
    }
}

#[no_mangle]
pub extern "C" fn cef_log(_file: *const c_char,
                          _line: c_int,
                          _severity: c_int,
                          message: *const c_char) {
    unsafe {
        let slice = ffi::CStr::from_ptr(message);
        println!("{}", str::from_utf8(slice.to_bytes()).unwrap())
    }
}

#[no_mangle]
pub extern "C" fn cef_get_min_log_level() -> c_int {
    0
}
<commit_msg>only create our own Display* in embedding when using OSR<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use command_line::command_line_init;
use interfaces::cef_app_t;
use types::{cef_main_args_t, cef_settings_t};
use window::init_window;

use libc::{c_char, c_int, c_void};
use util::opts;
use std::ffi;
use std::str;
use browser;
use std_url::Url;

const MAX_RENDERING_THREADS: usize = 128;

static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg";

static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
#[cfg(target_os="windows")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"5c7f3e50ff5265985d11dc1a466513e25748bedd\0";
#[cfg(target_os="macos")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"6813214accbf2ebfb6bdcf8d00654650b251bf3d\0";
#[cfg(target_os="linux")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e17fa17a6d\0";

#[no_mangle]
pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
                                 settings: *mut cef_settings_t,
                                 application: *mut cef_app_t,
                                 _windows_sandbox_info: *const c_void)
                                 -> c_int {
    if args.is_null() {
        return 0;
    }

    unsafe {
        command_line_init((*args).argc, (*args).argv);

        if !application.is_null() {
            (*application).get_browser_process_handler.map(|cb| {
                    let handler = cb(application);
                    if !handler.is_null() {
                        (*handler).on_context_initialized.map(|hcb| hcb(handler));
                    }
            });
        }
    }

    let rendering_threads = unsafe {
        if ((*settings).rendering_threads as usize) < 1 {
            1
        } else if (*settings).rendering_threads as usize > MAX_RENDERING_THREADS {
            MAX_RENDERING_THREADS
        } else {
            (*settings).rendering_threads as usize
        }
    };

    let mut temp_opts = opts::default_opts();
    temp_opts.paint_threads = rendering_threads;
    temp_opts.layout_threads = rendering_threads;
    temp_opts.headless = false;
    temp_opts.hard_fail = false;
    temp_opts.enable_text_antialiasing = true;
    temp_opts.resources_path = None;
    temp_opts.url = Url::parse(HOME_URL).unwrap();
    opts::set(temp_opts);

    if unsafe { (*settings).windowless_rendering_enabled != 0 } {
        init_window();
    }

    return 1
}

#[no_mangle]
pub extern "C" fn cef_shutdown() {
}

#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
    // GWTODO: Support blocking message loop
    // again. Although, will it ever actually
    // be used or will everything use the
    // cef_do_message_loop_work function below
    // as our current miniservo apps do?
    unimplemented!()
}

#[no_mangle]
pub extern "C" fn cef_do_message_loop_work() {
    browser::update();
}

#[no_mangle]
pub extern "C" fn cef_quit_message_loop() {
}

#[no_mangle]
pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t,
                                      _app: *mut cef_app_t,
                                      _windows_sandbox_info: *mut c_void)
                                      -> c_int {
    -1
}

#[no_mangle]
pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char {
    if entry == 0 {
        &CEF_API_HASH_PLATFORM[0] as *const u8 as *const c_char
    } else {
        &CEF_API_HASH_UNIVERSAL[0] as *const u8 as *const c_char
    }
}

#[no_mangle]
pub extern "C" fn cef_log(_file: *const c_char,
                          _line: c_int,
                          _severity: c_int,
                          message: *const c_char) {
    unsafe {
        let slice = ffi::CStr::from_ptr(message);
        println!("{}", str::from_utf8(slice.to_bytes()).unwrap())
    }
}

#[no_mangle]
pub extern "C" fn cef_get_min_log_level() -> c_int {
    0
}
<|endoftext|>


<commit_before>use time;
use std::io::timer::sleep;

use GameWindow;
use keyboard;
use mouse;
use event;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
#[deriving(Clone)]
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
#[deriving(Clone)]
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
#[deriving(Clone)]
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
#[deriving(Clone)]
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
#[deriving(Clone)]
pub struct MouseMoveArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Mouse relative move arguments.
#[deriving(Clone)]
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Mouse scroll arguments.
#[deriving(Clone)]
pub struct MouseScrollArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
    /// Scrolled mouse.
    MouseScroll(MouseScrollArgs)
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
/// loop {
///     match game_iter.next() {
///         None => break,
///         Some(mut e) => match e {
///             Render(ref mut args) => {
///                 // Create graphics context with absolute coordinates.
///                 let c = Context::abs(args.width as f64, args.height as f64);
///                 // Do rendering here.
///             },
///             _ => {},
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;
                    // Rendering code
                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_frame) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                    continue;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                    continue;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();

                    let updates_wanted =
                        (current_time as f64 - self.last_update as f64) /
                        self.dt_update_in_ns as f64;
                    let frames_wanted =
                        (current_time as f64 - self.last_frame as f64) /
                        self.dt_frame_in_ns as f64;

                    if updates_wanted >= 1.0 && updates_wanted > frames_wanted {
                        self.state = HandleEventsState;
                        continue;
                    }

                    if frames_wanted >= 1.0 {
                        self.state = RenderState;
                        continue;
                    }

                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    if next_frame > current_time && next_update > current_time {
                        let next_event = cmp::min(next_frame, next_update);
                        // Convert to ms because that is what the sleep function
                        // takes. Divide by 2 so we don't overshoot.
                        sleep( (next_event - current_time) / 1_000_000 / 2 );
                    }
                    continue;
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                            }))
                        },
                        event::MouseScrolled(x, y) => {
                            Some(MouseScroll(MouseScrollArgs {
                                x: x,
                                y: y
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            self.next()
                        },
                    }
                },
                MouseRelativeMoveState(dx, dy) => {
                    self.state = HandleEventsState;
                    return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                        dx: dx,
                        dy: dy,
                    }));
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update = time::precise_time_ns();
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };

            // TODO: make this not generate a warning, or enforce this condition
            // at compile-time.
            fail!(
                "{}{}{}{}",
                "Every state should explicitly return or explicitly loop, to ",
                "avoid accidentally looping forever. ",
                self.state,
                " did not."
            );
        }

        /*
        // copied.

        while !self.should_close(game_window) {

            let start_render = time::precise_time_ns();

            // Rendering code
            let (w, h) = game_window.get_size();
            if w != 0 && h != 0 {
                self.viewport(game_window);
                let mut gl = Gl::new(&mut gl_data, asset_store);
                bg.clear(&mut gl);
                // Extrapolate time forward to allow smooth motion.
                // 'now' is always bigger than 'last_update'.
                let ext_dt = (start_render - last_update) as f64 / billion as f64;
                self.render(
                    ext_dt,
                    &context
                        .trans(-1.0, 1.0)
                        .scale(2.0 / w as f64, -2.0 / h as f64)
                        .store_view(),
                    &mut gl
                        );
                self.swap_buffers(game_window);
            }

            let next_render = start_render + min_ns_per_frame;

            // Update gamestate
            let mut updated = 0;

            while // If we haven't reached the required number of updates yet
                  ( updated < min_updates_per_frame ||
                    // Or we have the time to update further
                    time::precise_time_ns() < next_render ) &&
                  //And we haven't already progressed time to far
                  last_update + update_time_in_ns < next_render {

                self.handle_events(game_window, asset_store);
                self.update(dt, asset_store);

                updated += 1;
                last_update += update_time_in_ns;
            }

            // Wait if possible

            let t = (next_render - time::precise_time_ns() ) / 1_000_000;
            if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                      // which tells us that t should have been negative
                                      // and we are running slow and shouldn't sleep.
                sleep( t );
            }

        }
        */
    }
}
<commit_msg>more comments from https://github.com/PistonDevelopers/piston/pull/524<commit_after>use time;
use std::io::timer::sleep;

use GameWindow;
use keyboard;
use mouse;
use event;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
#[deriving(Clone)]
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
#[deriving(Clone)]
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
#[deriving(Clone)]
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
#[deriving(Clone)]
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
#[deriving(Clone)]
pub struct MouseMoveArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Mouse relative move arguments.
#[deriving(Clone)]
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Mouse scroll arguments.
#[deriving(Clone)]
pub struct MouseScrollArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
    /// Scrolled mouse.
    MouseScroll(MouseScrollArgs)
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
/// loop {
///     match game_iter.next() {
///         None => break,
///         Some(mut e) => match e {
///             Render(ref mut args) => {
///                 // Create graphics context with absolute coordinates.
///                 let c = Context::abs(args.width as f64, args.height as f64);
///                 // Do rendering here.
///             },
///             _ => {},
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    self.last_frame += self.dt_frame_in_ns;

                    let start_render = time::precise_time_ns();
                    // Rendering code
                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_frame) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                    continue;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                    continue;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_frame > current_time && next_update > current_time {
                        sleep( (next_event - current_time) / 1_000_000 );
                    } else if next_event == next_frame {
                        self.state = RenderState;
                    } else {
                        self.state = HandleEventsState;
                    }
                    continue;
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                            }))
                        },
                        event::MouseScrolled(x, y) => {
                            Some(MouseScroll(MouseScrollArgs {
                                x: x,
                                y: y
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            continue;
                        },
                    }
                },
                MouseRelativeMoveState(dx, dy) => {
                    self.state = HandleEventsState;
                    return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                        dx: dx,
                        dy: dy,
                    }));
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };

            // TODO: make this not generate a warning, or enforce this condition
            // at compile-time.
            fail!(
                "{}{}{}{}",
                "Every state should explicitly return or explicitly loop, to ",
                "avoid accidentally looping forever. ",
                self.state,
                " did not."
            );
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::mem;
use std::cmp;
use std::str;

use solicit::Header;
use solicit::StreamId;
use solicit::HttpResult;
use solicit::frame::*;
use solicit::connection::ReceiveFrame;
use solicit::connection::HttpFrame;
use solicit::connection::SendFrame;
use solicit::connection::HttpConnection;
use solicit::connection::EndStream;
use solicit::connection::DataChunk;

use http_common::*;

/// work around https://github.com/mlalic/solicit/pull/33
#[allow(dead_code)]
pub struct OnceReceiveFrame {
    raw_frame: RawFrame,
    used: bool,
}

#[allow(dead_code)]
impl OnceReceiveFrame {
    pub fn new(raw_frame: RawFrame) -> OnceReceiveFrame {
        OnceReceiveFrame {
            raw_frame: raw_frame,
            used: false,
        }
    }
}

impl ReceiveFrame for OnceReceiveFrame {
    fn recv_frame(&mut self) -> HttpResult<HttpFrame> {
        assert!(!self.used);
        self.used = true;
        HttpFrame::from_raw(&self.raw_frame)
    }
}

pub struct VecSendFrame(pub Vec<u8>);

impl SendFrame for VecSendFrame {
    fn send_frame<F : FrameIR>(&mut self, frame: F) -> HttpResult<()> {
        let pos = self.0.len();
        let mut cursor = io::Cursor::new(mem::replace(&mut self.0, Vec::new()));
        cursor.set_position(pos as u64);
        frame.serialize_into(&mut cursor)?;
        self.0 = cursor.into_inner();

        Ok(())
    }
}

pub trait HttpConnectionEx {
    fn conn(&mut self) -> &mut HttpConnection;

    fn send_headers<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId,
        headers: &[Header],
        end_stream: EndStream)
            -> HttpResult<()>
    {
        self.conn().sender(send).send_headers(headers, stream_id, end_stream)
    }

    fn send_headers_to_vec(
        &mut self,
        stream_id: StreamId,
        headers: &[Header],
        end_stream: EndStream)
             -> HttpResult<Vec<u8>>
    {
        let mut send = VecSendFrame(Vec::new());
        self.send_headers(&mut send, stream_id, headers, end_stream)?;
        Ok(send.0)
    }

    fn send_data_frame<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId,
        chunk: &[u8],
        end_stream: EndStream)
            -> HttpResult<()>
    {
        let data_chunk = DataChunk::new_borrowed(chunk, stream_id, end_stream);
        self.conn().sender(send).send_data(data_chunk)
    }

    fn send_data_frames<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId,
        data: &[u8],
        end_stream: EndStream)
            -> HttpResult<()>
    {
        // if client requested end of stream,
        // we must send at least one frame with end stream flag
        if end_stream == EndStream::Yes && data.len() == 0 {
            return self.send_end_of_stream(send, stream_id)
        }

        let mut pos = 0;
        const MAX_CHUNK_SIZE: usize = 8 * 1024;
        while pos < data.len() {
            let end = cmp::min(data.len(), pos + MAX_CHUNK_SIZE);

            let end_stream =
                if end == data.len() && end_stream == EndStream::Yes {
                    EndStream::Yes
                } else {
                    EndStream::No
                };

            self.send_data_frame(send, stream_id, &data[pos..end], end_stream)?;

            pos = end;
        }

        Ok(())
    }

    fn send_data_frames_to_vec(
        &mut self,
        stream_id: StreamId,
        data: &[u8],
        end_stream: EndStream)
            -> HttpResult<Vec<u8>>
    {
        let mut send = VecSendFrame(Vec::new());
        self.send_data_frames(&mut send, stream_id, data, end_stream)?;
        Ok(send.0)
    }

    fn send_end_of_stream<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId)
            -> HttpResult<()>
    {
        self.send_data_frame(send, stream_id, &Vec::new(), EndStream::Yes)
    }

    fn send_end_of_stream_to_vec(&mut self, stream_id: StreamId) -> HttpResult<Vec<u8>> {
        let mut send = VecSendFrame(Vec::new());
        self.send_end_of_stream(&mut send, stream_id)?;
        Ok(send.0)
    }

    fn send_part<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId,
        part: &HttpStreamPart)
            -> HttpResult<()>
    {
        let end_stream = if part.last { EndStream::Yes } else { EndStream::No };
        match part.content {
            HttpStreamPartContent::Data(ref data) => self.send_data_frames(send, stream_id, &data, end_stream),
            HttpStreamPartContent::Headers(ref headers) => self.send_headers(send, stream_id, &headers, end_stream),
        }
    }

    fn send_part_to_vec(
        &mut self,
        stream_id: StreamId,
        part: &HttpStreamPart)
            -> HttpResult<Vec<u8>>
    {
        let mut send = VecSendFrame(Vec::new());
        self.send_part(&mut send, stream_id, part)?;
        Ok(send.0)
    }
}

impl HttpConnectionEx for HttpConnection {
    fn conn(&mut self) -> &mut HttpConnection {
        self
    }
}

/// Frames with stream
#[derive(Debug)]
pub enum HttpFrameStream {
    Data(DataFrame),
    Headers(HeadersFrame),
    RstStream(RstStreamFrame),
    WindowUpdate(WindowUpdateFrame),
}

impl HttpFrameStream {
    #[allow(dead_code)]
    pub fn into_frame(self) -> HttpFrame {
        match self {
            HttpFrameStream::WindowUpdate(f) => HttpFrame::WindowUpdateFrame(f),
            HttpFrameStream::Data(f) => HttpFrame::DataFrame(f),
            HttpFrameStream::Headers(f) => HttpFrame::HeadersFrame(f),
            HttpFrameStream::RstStream(f) => HttpFrame::RstStreamFrame(f),
        }
    }

    #[allow(dead_code)]
    pub fn get_stream_id(&self) -> StreamId {
        match self {
            &HttpFrameStream::WindowUpdate(ref f) => f.get_stream_id(),
            &HttpFrameStream::Data(ref f) => f.get_stream_id(),
            &HttpFrameStream::Headers(ref f) => f.get_stream_id(),
            &HttpFrameStream::RstStream(ref f) => f.get_stream_id(),
        }
    }

    #[allow(dead_code)]
    pub fn is_end_of_stream(&self) -> bool {
        match self {
            &HttpFrameStream::WindowUpdate(..) => false,
            &HttpFrameStream::Data(ref f) => f.is_end_of_stream(),
            &HttpFrameStream::Headers(ref f) => f.is_end_of_stream(),
            &HttpFrameStream::RstStream(..) => true,
        }
    }

}

/// Frames without stream (zero stream id)
#[derive(Debug)]
pub enum HttpFrameConn {
    Settings(SettingsFrame),
    Ping(PingFrame),
    Goaway(GoawayFrame),
    WindowUpdate(WindowUpdateFrame),
}

impl HttpFrameConn {
    #[allow(dead_code)]
    pub fn into_frame(self) -> HttpFrame {
        match self {
            HttpFrameConn::Settings(f) => HttpFrame::SettingsFrame(f),
            HttpFrameConn::Ping(f) => HttpFrame::PingFrame(f),
            HttpFrameConn::Goaway(f) => HttpFrame::GoawayFrame(f),
            HttpFrameConn::WindowUpdate(f) => HttpFrame::WindowUpdateFrame(f),
        }
    }
}

#[derive(Debug)]
pub enum HttpFrameClassified {
    Stream(HttpFrameStream),
    Conn(HttpFrameConn),
    Unknown(RawFrame),
}

impl HttpFrameClassified {
    pub fn from(frame: HttpFrame) -> Self {
        match frame {
            HttpFrame::DataFrame(f) => HttpFrameClassified::Stream(HttpFrameStream::Data(f)),
            HttpFrame::HeadersFrame(f) => HttpFrameClassified::Stream(HttpFrameStream::Headers(f)),
            HttpFrame::RstStreamFrame(f) => HttpFrameClassified::Stream(HttpFrameStream::RstStream(f)),
            HttpFrame::SettingsFrame(f) => HttpFrameClassified::Conn(HttpFrameConn::Settings(f)),
            HttpFrame::PingFrame(f) => HttpFrameClassified::Conn(HttpFrameConn::Ping(f)),
            HttpFrame::GoawayFrame(f) => HttpFrameClassified::Conn(HttpFrameConn::Goaway(f)),
            HttpFrame::WindowUpdateFrame(f) => {
                if f.get_stream_id() != 0 {
                    HttpFrameClassified::Stream(HttpFrameStream::WindowUpdate(f))
                } else {
                    HttpFrameClassified::Conn(HttpFrameConn::WindowUpdate(f))
                }
            },
            HttpFrame::UnknownFrame(f) => HttpFrameClassified::Unknown(f),
        }
    }

    pub fn from_raw(raw_frame: &RawFrame) -> HttpResult<HttpFrameClassified> {
        Ok(HttpFrameClassified::from(HttpFrame::from_raw(raw_frame)?))
    }
}

pub fn slice_get_header<'a>(headers: &'a [Header], name: &str) -> Option<&'a str> {
    headers.iter()
        .find(|h| h.name() == name.as_bytes())
        .and_then(|h| str::from_utf8(h.value()).ok())
}

<commit_msg>Purge unused code<commit_after>use std::io;
use std::mem;
use std::cmp;
use std::str;

use solicit::Header;
use solicit::StreamId;
use solicit::HttpResult;
use solicit::frame::*;
use solicit::connection::HttpFrame;
use solicit::connection::SendFrame;
use solicit::connection::HttpConnection;
use solicit::connection::EndStream;
use solicit::connection::DataChunk;

use http_common::*;

pub struct VecSendFrame(pub Vec<u8>);

impl SendFrame for VecSendFrame {
    fn send_frame<F : FrameIR>(&mut self, frame: F) -> HttpResult<()> {
        let pos = self.0.len();
        let mut cursor = io::Cursor::new(mem::replace(&mut self.0, Vec::new()));
        cursor.set_position(pos as u64);
        frame.serialize_into(&mut cursor)?;
        self.0 = cursor.into_inner();

        Ok(())
    }
}

pub trait HttpConnectionEx {
    fn conn(&mut self) -> &mut HttpConnection;

    fn send_headers<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId,
        headers: &[Header],
        end_stream: EndStream)
            -> HttpResult<()>
    {
        self.conn().sender(send).send_headers(headers, stream_id, end_stream)
    }

    fn send_headers_to_vec(
        &mut self,
        stream_id: StreamId,
        headers: &[Header],
        end_stream: EndStream)
             -> HttpResult<Vec<u8>>
    {
        let mut send = VecSendFrame(Vec::new());
        self.send_headers(&mut send, stream_id, headers, end_stream)?;
        Ok(send.0)
    }

    fn send_data_frame<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId,
        chunk: &[u8],
        end_stream: EndStream)
            -> HttpResult<()>
    {
        let data_chunk = DataChunk::new_borrowed(chunk, stream_id, end_stream);
        self.conn().sender(send).send_data(data_chunk)
    }

    fn send_data_frames<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId,
        data: &[u8],
        end_stream: EndStream)
            -> HttpResult<()>
    {
        // if client requested end of stream,
        // we must send at least one frame with end stream flag
        if end_stream == EndStream::Yes && data.len() == 0 {
            return self.send_end_of_stream(send, stream_id)
        }

        let mut pos = 0;
        const MAX_CHUNK_SIZE: usize = 8 * 1024;
        while pos < data.len() {
            let end = cmp::min(data.len(), pos + MAX_CHUNK_SIZE);

            let end_stream =
                if end == data.len() && end_stream == EndStream::Yes {
                    EndStream::Yes
                } else {
                    EndStream::No
                };

            self.send_data_frame(send, stream_id, &data[pos..end], end_stream)?;

            pos = end;
        }

        Ok(())
    }

    fn send_data_frames_to_vec(
        &mut self,
        stream_id: StreamId,
        data: &[u8],
        end_stream: EndStream)
            -> HttpResult<Vec<u8>>
    {
        let mut send = VecSendFrame(Vec::new());
        self.send_data_frames(&mut send, stream_id, data, end_stream)?;
        Ok(send.0)
    }

    fn send_end_of_stream<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId)
            -> HttpResult<()>
    {
        self.send_data_frame(send, stream_id, &Vec::new(), EndStream::Yes)
    }

    fn send_end_of_stream_to_vec(&mut self, stream_id: StreamId) -> HttpResult<Vec<u8>> {
        let mut send = VecSendFrame(Vec::new());
        self.send_end_of_stream(&mut send, stream_id)?;
        Ok(send.0)
    }

    fn send_part<S : SendFrame>(
        &mut self,
        send: &mut S,
        stream_id: StreamId,
        part: &HttpStreamPart)
            -> HttpResult<()>
    {
        let end_stream = if part.last { EndStream::Yes } else { EndStream::No };
        match part.content {
            HttpStreamPartContent::Data(ref data) => self.send_data_frames(send, stream_id, &data, end_stream),
            HttpStreamPartContent::Headers(ref headers) => self.send_headers(send, stream_id, &headers, end_stream),
        }
    }

    fn send_part_to_vec(
        &mut self,
        stream_id: StreamId,
        part: &HttpStreamPart)
            -> HttpResult<Vec<u8>>
    {
        let mut send = VecSendFrame(Vec::new());
        self.send_part(&mut send, stream_id, part)?;
        Ok(send.0)
    }
}

impl HttpConnectionEx for HttpConnection {
    fn conn(&mut self) -> &mut HttpConnection {
        self
    }
}

/// Frames with stream
#[derive(Debug)]
pub enum HttpFrameStream {
    Data(DataFrame),
    Headers(HeadersFrame),
    RstStream(RstStreamFrame),
    WindowUpdate(WindowUpdateFrame),
}

impl HttpFrameStream {
    #[allow(dead_code)]
    pub fn into_frame(self) -> HttpFrame {
        match self {
            HttpFrameStream::WindowUpdate(f) => HttpFrame::WindowUpdateFrame(f),
            HttpFrameStream::Data(f) => HttpFrame::DataFrame(f),
            HttpFrameStream::Headers(f) => HttpFrame::HeadersFrame(f),
            HttpFrameStream::RstStream(f) => HttpFrame::RstStreamFrame(f),
        }
    }

    #[allow(dead_code)]
    pub fn get_stream_id(&self) -> StreamId {
        match self {
            &HttpFrameStream::WindowUpdate(ref f) => f.get_stream_id(),
            &HttpFrameStream::Data(ref f) => f.get_stream_id(),
            &HttpFrameStream::Headers(ref f) => f.get_stream_id(),
            &HttpFrameStream::RstStream(ref f) => f.get_stream_id(),
        }
    }

    #[allow(dead_code)]
    pub fn is_end_of_stream(&self) -> bool {
        match self {
            &HttpFrameStream::WindowUpdate(..) => false,
            &HttpFrameStream::Data(ref f) => f.is_end_of_stream(),
            &HttpFrameStream::Headers(ref f) => f.is_end_of_stream(),
            &HttpFrameStream::RstStream(..) => true,
        }
    }

}

/// Frames without stream (zero stream id)
#[derive(Debug)]
pub enum HttpFrameConn {
    Settings(SettingsFrame),
    Ping(PingFrame),
    Goaway(GoawayFrame),
    WindowUpdate(WindowUpdateFrame),
}

impl HttpFrameConn {
    #[allow(dead_code)]
    pub fn into_frame(self) -> HttpFrame {
        match self {
            HttpFrameConn::Settings(f) => HttpFrame::SettingsFrame(f),
            HttpFrameConn::Ping(f) => HttpFrame::PingFrame(f),
            HttpFrameConn::Goaway(f) => HttpFrame::GoawayFrame(f),
            HttpFrameConn::WindowUpdate(f) => HttpFrame::WindowUpdateFrame(f),
        }
    }
}

#[derive(Debug)]
pub enum HttpFrameClassified {
    Stream(HttpFrameStream),
    Conn(HttpFrameConn),
    Unknown(RawFrame),
}

impl HttpFrameClassified {
    pub fn from(frame: HttpFrame) -> Self {
        match frame {
            HttpFrame::DataFrame(f) => HttpFrameClassified::Stream(HttpFrameStream::Data(f)),
            HttpFrame::HeadersFrame(f) => HttpFrameClassified::Stream(HttpFrameStream::Headers(f)),
            HttpFrame::RstStreamFrame(f) => HttpFrameClassified::Stream(HttpFrameStream::RstStream(f)),
            HttpFrame::SettingsFrame(f) => HttpFrameClassified::Conn(HttpFrameConn::Settings(f)),
            HttpFrame::PingFrame(f) => HttpFrameClassified::Conn(HttpFrameConn::Ping(f)),
            HttpFrame::GoawayFrame(f) => HttpFrameClassified::Conn(HttpFrameConn::Goaway(f)),
            HttpFrame::WindowUpdateFrame(f) => {
                if f.get_stream_id() != 0 {
                    HttpFrameClassified::Stream(HttpFrameStream::WindowUpdate(f))
                } else {
                    HttpFrameClassified::Conn(HttpFrameConn::WindowUpdate(f))
                }
            },
            HttpFrame::UnknownFrame(f) => HttpFrameClassified::Unknown(f),
        }
    }

    pub fn from_raw(raw_frame: &RawFrame) -> HttpResult<HttpFrameClassified> {
        Ok(HttpFrameClassified::from(HttpFrame::from_raw(raw_frame)?))
    }
}

pub fn slice_get_header<'a>(headers: &'a [Header], name: &str) -> Option<&'a str> {
    headers.iter()
        .find(|h| h.name() == name.as_bytes())
        .and_then(|h| str::from_utf8(h.value()).ok())
}

<|endoftext|>


<commit_before>#[crate_id = "hamcrest"];

use std::task;
use std::fmt::Show;

pub struct Description {
  msg: ~str
}

impl Description {
  pub fn new() -> Description {
    Description { msg: ~"" }
  }

  pub fn append_text<'r>(&'r mut self, item: &str) -> &'r mut Description {
    self.msg = self.msg + item;
    self
  }

  pub fn append_description_of<'r>(&'r mut self, item: &SelfDescribing) -> &'r mut Description {
    item.describe_to(self);
    self
  }

  pub fn to_str<'r>(&'r self) -> &'r str {
    self.msg.as_slice()
  }
}

pub trait SelfDescribing {

  fn describe_to(&self, desc: &mut Description) {
    desc.append_text(format!("{:?}", self));
  }

}

pub trait Matcher<T> : SelfDescribing + Clone {
  fn matches(&self, actual: &T) -> bool;

  fn describe_mismatch(&self, _: &T, desc: &mut Description) {
    desc.append_text(format!("was {:?}", self));
  }
}

/*
 *
 * ===== Is =====
 *
 */

#[deriving(Clone)]
struct Is<T, M> {
  matcher: M
}

impl<T, M : Matcher<T>> SelfDescribing for Is<T, M> {
  fn describe_to(&self, desc: &mut Description) {
    self.matcher.describe_to(desc);
  }
}

impl<T : Clone, M : Matcher<T>> Matcher<T> for Is<T, M> {
  fn matches(&self, actual: &T) -> bool {
    self.matcher.matches(actual)
  }

  fn describe_mismatch(&self, actual: &T, desc: &mut Description) {
    self.matcher.describe_mismatch(actual, desc);
  }
}

fn is<T, M: Matcher<T>>(matcher: M) -> Is<T, M> {
  Is { matcher: matcher.clone() }
}

/*
 *
 * ===== EqualTo =====
 *
 */

#[deriving(Clone)]
struct EqualTo<T> {
  expected: T
}

impl<T : Show> SelfDescribing for EqualTo<T> {
  fn describe_to(&self, desc: &mut Description) {
    desc.append_text(format!("{}", self.expected));
  }
}

impl<T : Eq + Clone + Show> Matcher<T> for EqualTo<T> {
  fn matches(&self, actual: &T) -> bool {
    self.expected.eq(actual)
  }

  fn describe_mismatch(&self, actual: &T, desc: &mut Description) {
    desc.append_text(format!("was {}", actual));
  }
}

fn equal_to<T : Eq + Clone + Show>(expected: &T) -> EqualTo<T> {
  EqualTo { expected: expected.clone() }
}

/*
 *
 * ===== Assertion =====
 *
 */

fn assert_that<T: Clone, U: Matcher<T> + SelfDescribing>(actual: T, matcher: U) {
  if !matcher.matches(&actual) {
    let mut desc = Description::new();

    desc
      .append_text("\nExpected: ")
      .append_description_of(&matcher as &SelfDescribing)
      .append_text("\n     but: ");

    matcher.describe_mismatch(&actual, &mut desc);

    fail!("{}", desc.to_str());
  }
}

#[test]
fn test_equality_of_ints() {
  // Successful match
  assert_that(1, is(equal_to(&1)));

  // Unsuccessful match
  let res = task::try(proc() {
    assert_that(2, is(equal_to(&1)));
  });

  assert!(res.is_err());
}
<commit_msg>Export public members<commit_after>#[crate_id = "hamcrest"];

use std::task;
use std::fmt::Show;

pub struct Description {
  msg: ~str
}

impl Description {
  pub fn new() -> Description {
    Description { msg: ~"" }
  }

  pub fn append_text<'r>(&'r mut self, item: &str) -> &'r mut Description {
    self.msg = self.msg + item;
    self
  }

  pub fn append_description_of<'r>(&'r mut self, item: &SelfDescribing) -> &'r mut Description {
    item.describe_to(self);
    self
  }

  pub fn to_str<'r>(&'r self) -> &'r str {
    self.msg.as_slice()
  }
}

pub trait SelfDescribing {

  fn describe_to(&self, desc: &mut Description) {
    desc.append_text(format!("{:?}", self));
  }

}

pub trait Matcher<T> : SelfDescribing + Clone {
  fn matches(&self, actual: &T) -> bool;

  fn describe_mismatch(&self, _: &T, desc: &mut Description) {
    desc.append_text(format!("was {:?}", self));
  }
}

/*
 *
 * ===== Is =====
 *
 */

#[deriving(Clone)]
struct Is<T, M> {
  matcher: M
}

impl<T, M : Matcher<T>> SelfDescribing for Is<T, M> {
  fn describe_to(&self, desc: &mut Description) {
    self.matcher.describe_to(desc);
  }
}

impl<T : Clone, M : Matcher<T>> Matcher<T> for Is<T, M> {
  fn matches(&self, actual: &T) -> bool {
    self.matcher.matches(actual)
  }

  fn describe_mismatch(&self, actual: &T, desc: &mut Description) {
    self.matcher.describe_mismatch(actual, desc);
  }
}

fn is<T, M: Matcher<T>>(matcher: M) -> Is<T, M> {
  Is { matcher: matcher.clone() }
}

/*
 *
 * ===== EqualTo =====
 *
 */

#[deriving(Clone)]
pub struct EqualTo<T> {
  expected: T
}

impl<T : Show> SelfDescribing for EqualTo<T> {
  fn describe_to(&self, desc: &mut Description) {
    desc.append_text(format!("{}", self.expected));
  }
}

impl<T : Eq + Clone + Show> Matcher<T> for EqualTo<T> {
  fn matches(&self, actual: &T) -> bool {
    self.expected.eq(actual)
  }

  fn describe_mismatch(&self, actual: &T, desc: &mut Description) {
    desc.append_text(format!("was {}", actual));
  }
}

pub fn equal_to<T : Eq + Clone + Show>(expected: &T) -> EqualTo<T> {
  EqualTo { expected: expected.clone() }
}

/*
 *
 * ===== Assertion =====
 *
 */

pub fn assert_that<T: Clone, U: Matcher<T> + SelfDescribing>(actual: T, matcher: U) {
  if !matcher.matches(&actual) {
    let mut desc = Description::new();

    desc
      .append_text("\nExpected: ")
      .append_description_of(&matcher as &SelfDescribing)
      .append_text("\n     but: ");

    matcher.describe_mismatch(&actual, &mut desc);

    fail!("{}", desc.to_str());
  }
}

#[test]
fn test_equality_of_ints() {
  // Successful match
  assert_that(1, is(equal_to(&1)));

  // Unsuccessful match
  let res = task::try(proc() {
    assert_that(2, is(equal_to(&1)));
  });

  assert!(res.is_err());
}
<|endoftext|>


<commit_before>//! Http I/O streams definitions

use std::net::{ToSocketAddrs, TcpStream};
use std::io::{Error, Read, Write};
#[cfg(feature="ssl")]
use std::io::ErrorKind;

/// Represent a type that can be opened (ie connected) to a remote `SocketAddress`
pub trait Open: Sized {
	/// Create a new Instance of `Self` connected to `addr`
	fn open<A: ToSocketAddrs>(addr: A) -> Result<Self, Error>;
}

/// A trait representing an openable read/write stream
pub trait Stream: Read+Write+Open {}

/// HttpStream for unsecured HTTP Input/Output
pub type HttpStream = TcpStream;
impl Stream for HttpStream{}

impl Open for HttpStream {
	fn open<A: ToSocketAddrs>(addr: A) -> Result<HttpStream, Error> {
		return Ok(try!(TcpStream::connect(addr)));
	}
}

#[cfg(feature="ssl")]
use openssl::ssl::{SslContext, SslStream, SslMethod};

/// HttpsStream for secured HTTPS Input/Output. Only available if "ssl" feature is enabled
#[cfg(feature="ssl")]
pub type HttpsStream = SslStream<TcpStream>;
#[cfg(feature="ssl")]
impl Stream for HttpsStream{}

#[cfg(feature="ssl")]
impl Open for HttpsStream {
	fn open<A: ToSocketAddrs>(addr: A) -> Result<HttpsStream, Error> {
		let ctx = match SslContext::new(SslMethod::Tlsv1) {
			Ok(c) => c,
			Err(e) => return Err(Error::new(ErrorKind::Other, format!("Cannot create SSL context : {}", e)))
		};
		let sock = try!(TcpStream::connect(addr));
		let stream = match SslStream::connect(&ctx, sock) {
			Ok(s) => s,
			Err(e) => return Err(Error::new(ErrorKind::Other, format!("Cannot create SSL stream : {}", e)))
		};
		return Ok(stream);
	}
}
<commit_msg>Fixed build<commit_after>//! Http I/O streams definitions

use std::net::{ToSocketAddrs, TcpStream};
use std::io::{Error, Read, Write};
#[cfg(feature="ssl")]
use std::io::ErrorKind;

/// Represent a type that can be opened (ie connected) to a remote `SocketAddress`
pub trait Open: Sized {
	/// Create a new Instance of `Self` connected to `addr`
	fn open<A: ToSocketAddrs>(addr: A) -> Result<Self, Error>;
}

/// A trait representing an openable read/write stream
pub trait Stream: Read+Write+Open {}

/// HttpStream for unsecured HTTP Input/Output
pub type HttpStream = TcpStream;
impl Stream for HttpStream{}

impl Open for HttpStream {
	fn open<A: ToSocketAddrs>(addr: A) -> Result<HttpStream, Error> {
		return Ok(try!(TcpStream::connect(addr)));
	}
}

#[cfg(feature="ssl")]
use openssl::ssl::{SslStream, SslMethod, SslConnectorBuilder};

/// HttpsStream for secured HTTPS Input/Output. Only available if "ssl" feature is enabled
#[cfg(feature="ssl")]
pub type HttpsStream = SslStream<TcpStream>;
#[cfg(feature="ssl")]
impl Stream for HttpsStream{}

#[cfg(feature="ssl")]
impl Open for HttpsStream {
	fn open<A: ToSocketAddrs>(addr: A) -> Result<HttpsStream, Error> {
		let sock = try!(TcpStream::connect(addr));
		let builder = match SslConnectorBuilder::new(SslMethod::tls()) {
			Ok(s) => s.build(),
			Err(e) => return Err(Error::new(ErrorKind::Other, format!("Cannot create SSL stream : {}", e)))
		};
		let stream = match builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(sock) {
			Ok(s) => s,
			Err(e) => return Err(Error::new(ErrorKind::Other, format!("Cannot create SSL stream : {}", e)))
		};
		return Ok(stream);
	}
}
<|endoftext|>


<commit_before>mod terminal;
mod ansi;

use std::io::{self, Write};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, cursor, style};
use rayon::prelude::*;
use rff::choice::Choice;

#[derive(Debug)]
pub enum Error {
    Exit,
    Write(io::Error),
    Reset(terminal::Error)
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Write(err)
    }
}

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    selected: usize,
    search: String,
    terminal: Terminal
}

impl Interface {
    /// Creates a new Interface with the provided input choices.
    pub fn with_choices(choices: Vec<String>) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: choices,
            matching: Vec::new(),
            selected: 0,
            search: String::new(),
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_choices();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') | Key::Ctrl('d') => {
                        self.clear()?;
                        return Err(Error::Exit);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.
                            checked_sub(1).
                            unwrap_or(0);

                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_choices();
                        self.render()?;
                    },

                    Key::Backspace | Key::Ctrl('h') => {
                        self.search.pop();
                        self.filter_choices();
                        self.render()?;
                    }

                    Key::Ctrl('u') => {
                        self.search.clear();
                        self.filter_choices();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.clear()?;
        Ok(self.result())
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            par_iter().
            cloned().
            filter_map(|choice| Choice::new(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        write!(self.terminal, "> {}", self.search)?;

        let n = self.render_choices()?;

        if n > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(self.terminal, "{}{}", cursor::Up(n), cursor::Column(column + 1))?;
        }

        Ok(())
    }

    fn render_choices(&mut self) -> io::Result<u16> {
        let max_width = self.terminal.max_width as usize;

        let choices = self.matching.
            iter().
            map(|c| c.text()).
            map(|c| {
                c.chars().take(max_width).collect::<String>()
            }).take(10);

        let number_of_choices = choices.len() as u16;

        for (i, choice) in choices.enumerate() {
            write!(self.terminal, "\r\n")?;

            if i == self.selected {
                let invert = style::Invert;
                let reset = style::NoInvert;
                write!(self.terminal, "{}{}{}", invert, choice, reset)?;
            } else {
                write!(self.terminal, "{}", choice)?;
            }
        }

        Ok(number_of_choices)
    }

    #[inline(always)]
    fn clamp_selected(&mut self) {
        let mut max = self.matching.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = max - 1;
        }
    }

    fn clear(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matching.iter().
            map(|c| c.text()).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<commit_msg>Speed up additive filtering by reusing matches<commit_after>mod terminal;
mod ansi;

use std::io::{self, Write};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, cursor, style};
use rayon::prelude::*;
use rff::choice::Choice;

#[derive(Debug)]
pub enum Error {
    Exit,
    Write(io::Error),
    Reset(terminal::Error)
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Write(err)
    }
}

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    selected: usize,
    search: String,
    terminal: Terminal
}

impl Interface {
    /// Creates a new Interface with the provided input choices.
    pub fn with_choices(choices: Vec<String>) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: choices,
            matching: Vec::new(),
            selected: 0,
            search: String::new(),
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_choices();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') | Key::Ctrl('d') => {
                        self.clear()?;
                        return Err(Error::Exit);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.
                            checked_sub(1).
                            unwrap_or(0);

                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_existing_matches();
                        self.render()?;
                    },

                    Key::Backspace | Key::Ctrl('h') => {
                        self.search.pop();
                        self.filter_choices();
                        self.render()?;
                    }

                    Key::Ctrl('u') => {
                        self.search.clear();
                        self.filter_choices();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.clear()?;
        Ok(self.result())
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            par_iter().
            cloned().
            filter_map(|choice| Choice::new(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn filter_existing_matches(&mut self) {
        let mut matches = self.matching.
            par_iter().
            map(|c| c.text().to_string()).
            filter_map(|choice| Choice::new(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        write!(self.terminal, "> {}", self.search)?;

        let n = self.render_choices()?;

        if n > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(self.terminal, "{}{}", cursor::Up(n), cursor::Column(column + 1))?;
        }

        Ok(())
    }

    fn render_choices(&mut self) -> io::Result<u16> {
        let max_width = self.terminal.max_width as usize;

        let choices = self.matching.
            iter().
            map(|c| c.text()).
            map(|c| {
                c.chars().take(max_width).collect::<String>()
            }).take(10);

        let number_of_choices = choices.len() as u16;

        for (i, choice) in choices.enumerate() {
            write!(self.terminal, "\r\n")?;

            if i == self.selected {
                let invert = style::Invert;
                let reset = style::NoInvert;
                write!(self.terminal, "{}{}{}", invert, choice, reset)?;
            } else {
                write!(self.terminal, "{}", choice)?;
            }
        }

        Ok(number_of_choices)
    }

    #[inline(always)]
    fn clamp_selected(&mut self) {
        let mut max = self.matching.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = max - 1;
        }
    }

    fn clear(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matching.iter().
            map(|c| c.text()).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

    pub fn len(&self) -> usize {
        self.buffers.len()
    }

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.buffers.is_empty()
    }

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    // Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    // assigned it is never changed. They can be reused, or even not used (we only allocate them
    // for our convenience, and they do not need to go up monotonically like buffer ids do).
    // For new buffers not backed by a file "new", then "new<1>" etc.
    // For buffers backed by a file, the leaf filename, then <1> etc.
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use std::path::PathBuf;
    use super::super::BufferFactory;

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<commit_msg>Buffers: start new function get_unique_title().<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

    pub fn len(&self) -> usize {
        self.buffers.len()
    }

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.buffers.is_empty()
    }

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    /// Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    /// assigned it is never changed. They can be reused, or even not used (we only allocate them
    /// for our convenience, and they do not need to go up monotonically like buffer ids do).
    /// For new buffers not backed by a file "new", then "new 1 " etc.
    /// For buffers backed by a file, the leaf filename, then '1' etc.
    fn get_unique_title(&self, proposed: &str) -> String {
        //let matching_buffers : Vec<_> = self.buffers.values().filter(
        //    |refcell| refcell.borrow().title == proposed).collect();

        let prefix = String::from(proposed) + " ";
        let matching_buffers = self.buffers.values()
            .filter(|refcell| refcell.borrow().title == proposed || refcell.borrow().title.starts_with(&prefix));

        let cnt = matching_buffers.count();
        if cnt == 0 {
            return String::from(proposed);
        } else if cnt == 1 {
            return String::from(proposed) + " 1";
        }

        String::default()
    }
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use super::super::BufferFactory;

    #[test]
    fn get_unique_title_for_empty_collection_returns_proposed() {
        let bc = BufferCollection::new();
        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_no_matching_buffer_title_returns_proposed() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_title_returns_proposed_with_numeral_of_one() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 1");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_in_ascending_order_returns_proposed_with_next_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 3");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_with_gap_returns_proposed_with_lowest_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 3");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 2");
    }

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<|endoftext|>


<commit_before>use crate::{manager::service::Service,
            util};
use habitat_core::{env,
                   package::PackageIdent,
                   service::ServiceGroup,
                   ChannelIdent};
use std::{self,
          time::Duration};
use tokio::{self,
            time};

// TODO (CM): Yes, the variable value should be "period" and not
// "frequency"... we need to fix that.
const PERIOD_BYPASS_CHECK_ENVVAR: &str = "HAB_UPDATE_STRATEGY_FREQUENCY_BYPASS_CHECK";

habitat_core::env_config_duration!(
    /// Represents how far apart checks for updates to individual services
    /// are, in milliseconds.
    PackageUpdateWorkerPeriod,
    // TODO (CM): Yes, the variable value should be "period" and not
    // "frequency"... we need to fix that.
    HAB_UPDATE_STRATEGY_FREQUENCY_MS => from_millis,
    PackageUpdateWorkerPeriod::MIN_ALLOWED);

impl PackageUpdateWorkerPeriod {
    const MIN_ALLOWED: Duration = Duration::from_secs(60);

    fn get() -> Duration {
        let val = PackageUpdateWorkerPeriod::configured_value().into();
        if val >= PackageUpdateWorkerPeriod::MIN_ALLOWED
           || env::var(PERIOD_BYPASS_CHECK_ENVVAR).is_ok()
        {
            val
        } else {
            PackageUpdateWorkerPeriod::MIN_ALLOWED
        }
    }
}

/// When `run`, a `PackageUpdateWorker` returns a future that continuously checks for a change in
/// version of the package being run by a service. If a change is detected, the package is installed
/// and its identifier returned.
pub struct PackageUpdateWorker {
    service_group: ServiceGroup,
    ident:         PackageIdent,
    // TODO (DM): This field should always be fully qualified. We need a
    // type to encapsulate that.
    full_ident:    PackageIdent,
    channel:       ChannelIdent,
    builder_url:   String,
}

impl From<&Service> for PackageUpdateWorker {
    fn from(service: &Service) -> Self {
        Self { service_group: service.service_group.clone(),
               ident:         service.spec_ident.clone(),
               full_ident:    service.pkg.ident.clone(),
               channel:       service.channel.clone(),
               builder_url:   service.bldr_url.clone(), }
    }
}

impl PackageUpdateWorker {
    /// The package update worker future.
    ///
    /// If no `install_ident` is specified the service ident is used when searching for the package.
    /// If an `install_ident` is specified, it is used when searching for a package. If a fully
    /// qualified package ident is used, the future will only resolve when that exact package is
    /// found.
    // TODO (DM): The returned package ident should always be fully qualified. We need a type to
    // encapsulate that.
    pub async fn run(&self, install_ident: Option<PackageIdent>) -> PackageIdent {
        let install_ident = install_ident.unwrap_or_else(|| self.ident.clone());
        let install_source = install_ident.clone().into();
        loop {
            // TODO (DM): The entire behavior of the updater depends on this `install` function. It
            // is what the old updater used, but its exact behavior should be tested/documented.
            match util::pkg::install_no_ui(&self.builder_url, &install_source, &self.channel).await
            {
                Ok(package) => {
                    // Only allow updates never rollbacks.
                    if package.ident > self.full_ident {
                        debug!("'{}' package update worker found change from '{}' to '{}' for \
                                '{}' in channel '{}'",
                               self.service_group,
                               self.full_ident,
                               package.ident,
                               install_ident,
                               self.channel,);
                        break package.ident;
                    } else {
                        trace!("'{}' package update worker did not find change from '{}' for '{}' \
                                in channel '{}'",
                               self.service_group,
                               self.full_ident,
                               install_ident,
                               self.channel,)
                    }
                }
                Err(err) => {
                    warn!("'{}' package update worker failed to install '{}' from channel '{}', \
                           err: {}",
                          self.service_group, self.ident, self.channel, err)
                }
            }
            time::delay_for(PackageUpdateWorkerPeriod::get()).await;
        }
    }
}

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

    #[test]
    fn worker_period_default_is_equal_to_minimum_allowed_value() {
        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::MIN_ALLOWED);
    }

    locked_env_var!(HAB_UPDATE_STRATEGY_FREQUENCY_MS, lock_period_var);
    locked_env_var!(HAB_UPDATE_STRATEGY_FREQUENCY_BYPASS_CHECK, lock_bypass_var);

    #[test]
    fn worker_period_must_be_positive() {
        use std::str::FromStr as _;
        assert!(PackageUpdateWorkerPeriod::from_str("-123").is_err());
        assert!(PackageUpdateWorkerPeriod::from_str("0").is_ok());
        assert!(PackageUpdateWorkerPeriod::from_str("5").is_ok());
    }

    #[test]
    fn worker_period_must_be_bypassed_by_non_empty_value() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("123");
        bypass.set(""); // empty string isn't allowed

        assert_ne!(PackageUpdateWorkerPeriod::get(), Duration::from_millis(123));
        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_defaults_properly() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.unset();
        bypass.unset();

        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_can_be_overridden_by_env_var() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("120000");
        bypass.unset();
        let expected_period: PackageUpdateWorkerPeriod =
            PackageUpdateWorkerPeriod(Duration::from_millis(120_000));
        assert!(expected_period.0 >= PackageUpdateWorkerPeriod::MIN_ALLOWED);
        assert_eq!(expected_period.0, PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_cannot_be_overridden_to_a_very_small_value_by_default() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("1"); // This is TOO low
        bypass.unset();
        assert!(Duration::from_millis(1) < PackageUpdateWorkerPeriod::MIN_ALLOWED);
        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_cannot_be_overridden_by_a_non_number() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("this is not a number");
        bypass.unset();
        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_can_be_overridden_by_a_small_value_with_bypass_var() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("5000");
        bypass.set("1");
        let expected_period: PackageUpdateWorkerPeriod =
            PackageUpdateWorkerPeriod(Duration::from_millis(5000));
        assert!(expected_period.0 < PackageUpdateWorkerPeriod::MIN_ALLOWED);
        assert_eq!(expected_period.0, PackageUpdateWorkerPeriod::get());
    }
}
<commit_msg>Cache delay in package upate worker<commit_after>use crate::{manager::service::Service,
            util};
use habitat_core::{env,
                   package::PackageIdent,
                   service::ServiceGroup,
                   ChannelIdent};
use std::{self,
          time::Duration};
use tokio::{self,
            time};

// TODO (CM): Yes, the variable value should be "period" and not
// "frequency"... we need to fix that.
const PERIOD_BYPASS_CHECK_ENVVAR: &str = "HAB_UPDATE_STRATEGY_FREQUENCY_BYPASS_CHECK";

habitat_core::env_config_duration!(
    /// Represents how far apart checks for updates to individual services
    /// are, in milliseconds.
    PackageUpdateWorkerPeriod,
    // TODO (CM): Yes, the variable value should be "period" and not
    // "frequency"... we need to fix that.
    HAB_UPDATE_STRATEGY_FREQUENCY_MS => from_millis,
    PackageUpdateWorkerPeriod::MIN_ALLOWED);

impl PackageUpdateWorkerPeriod {
    const MIN_ALLOWED: Duration = Duration::from_secs(60);

    fn get() -> Duration {
        let val = PackageUpdateWorkerPeriod::configured_value().into();
        if val >= PackageUpdateWorkerPeriod::MIN_ALLOWED
           || env::var(PERIOD_BYPASS_CHECK_ENVVAR).is_ok()
        {
            val
        } else {
            PackageUpdateWorkerPeriod::MIN_ALLOWED
        }
    }
}

/// When `run`, a `PackageUpdateWorker` returns a future that continuously checks for a change in
/// version of the package being run by a service. If a change is detected, the package is installed
/// and its identifier returned.
pub struct PackageUpdateWorker {
    service_group: ServiceGroup,
    ident:         PackageIdent,
    // TODO (DM): This field should always be fully qualified. We need a
    // type to encapsulate that.
    full_ident:    PackageIdent,
    channel:       ChannelIdent,
    builder_url:   String,
}

impl From<&Service> for PackageUpdateWorker {
    fn from(service: &Service) -> Self {
        Self { service_group: service.service_group.clone(),
               ident:         service.spec_ident.clone(),
               full_ident:    service.pkg.ident.clone(),
               channel:       service.channel.clone(),
               builder_url:   service.bldr_url.clone(), }
    }
}

impl PackageUpdateWorker {
    /// The package update worker future.
    ///
    /// If no `install_ident` is specified the service ident is used when searching for the package.
    /// If an `install_ident` is specified, it is used when searching for a package. If a fully
    /// qualified package ident is used, the future will only resolve when that exact package is
    /// found.
    // TODO (DM): The returned package ident should always be fully qualified. We need a type to
    // encapsulate that.
    pub async fn run(&self, install_ident: Option<PackageIdent>) -> PackageIdent {
        let install_ident = install_ident.unwrap_or_else(|| self.ident.clone());
        let install_source = install_ident.clone().into();
        let delay = PackageUpdateWorkerPeriod::get();
        loop {
            // TODO (DM): The entire behavior of the updater depends on this `install` function. It
            // is what the old updater used, but its exact behavior should be tested/documented.
            match util::pkg::install_no_ui(&self.builder_url, &install_source, &self.channel).await
            {
                Ok(package) => {
                    // Only allow updates never rollbacks.
                    if package.ident > self.full_ident {
                        debug!("'{}' package update worker found change from '{}' to '{}' for \
                                '{}' in channel '{}'",
                               self.service_group,
                               self.full_ident,
                               package.ident,
                               install_ident,
                               self.channel,);
                        break package.ident;
                    } else {
                        trace!("'{}' package update worker did not find change from '{}' for '{}' \
                                in channel '{}'",
                               self.service_group,
                               self.full_ident,
                               install_ident,
                               self.channel,)
                    }
                }
                Err(err) => {
                    warn!("'{}' package update worker failed to install '{}' from channel '{}', \
                           err: {}",
                          self.service_group, self.ident, self.channel, err)
                }
            }
            time::delay_for(delay).await;
        }
    }
}

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

    #[test]
    fn worker_period_default_is_equal_to_minimum_allowed_value() {
        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::MIN_ALLOWED);
    }

    locked_env_var!(HAB_UPDATE_STRATEGY_FREQUENCY_MS, lock_period_var);
    locked_env_var!(HAB_UPDATE_STRATEGY_FREQUENCY_BYPASS_CHECK, lock_bypass_var);

    #[test]
    fn worker_period_must_be_positive() {
        use std::str::FromStr as _;
        assert!(PackageUpdateWorkerPeriod::from_str("-123").is_err());
        assert!(PackageUpdateWorkerPeriod::from_str("0").is_ok());
        assert!(PackageUpdateWorkerPeriod::from_str("5").is_ok());
    }

    #[test]
    fn worker_period_must_be_bypassed_by_non_empty_value() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("123");
        bypass.set(""); // empty string isn't allowed

        assert_ne!(PackageUpdateWorkerPeriod::get(), Duration::from_millis(123));
        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_defaults_properly() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.unset();
        bypass.unset();

        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_can_be_overridden_by_env_var() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("120000");
        bypass.unset();
        let expected_period: PackageUpdateWorkerPeriod =
            PackageUpdateWorkerPeriod(Duration::from_millis(120_000));
        assert!(expected_period.0 >= PackageUpdateWorkerPeriod::MIN_ALLOWED);
        assert_eq!(expected_period.0, PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_cannot_be_overridden_to_a_very_small_value_by_default() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("1"); // This is TOO low
        bypass.unset();
        assert!(Duration::from_millis(1) < PackageUpdateWorkerPeriod::MIN_ALLOWED);
        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_cannot_be_overridden_by_a_non_number() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("this is not a number");
        bypass.unset();
        assert_eq!(PackageUpdateWorkerPeriod::default().0,
                   PackageUpdateWorkerPeriod::get());
    }

    #[test]
    fn worker_period_can_be_overridden_by_a_small_value_with_bypass_var() {
        let period = lock_period_var();
        let bypass = lock_bypass_var();

        period.set("5000");
        bypass.set("1");
        let expected_period: PackageUpdateWorkerPeriod =
            PackageUpdateWorkerPeriod(Duration::from_millis(5000));
        assert!(expected_period.0 < PackageUpdateWorkerPeriod::MIN_ALLOWED);
        assert_eq!(expected_period.0, PackageUpdateWorkerPeriod::get());
    }
}
<|endoftext|>