<commit_before>//! This module contains a platform specific implementation of the window shell.
use std::sync::mpsc;
use stdweb::{js, web::window};

use crate::prelude::*;

use self::states::*;
pub use self::window::*;
pub use self::window_builder::*;

mod states;
mod window;
mod window_builder;

fn set_panic_hook() {
    // When the `console_error_panic_hook` feature is enabled, we can call the
    // `set_panic_hook` function at least once during initialization, and then
    // we will get better error messages if our code ever panics.
    //
    // For more details see
    // https://github.com/rustwasm/console_error_panic_hook#readme
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

/// Initializes web stuff.
pub fn initialize() {
    set_panic_hook();
    stdweb::initialize();
}

/// Represents an application shell that could handle multiple windows.
pub struct Shell
where
    A: WindowAdapter,
{
    window_shells: Vec<Window>,
    requests: mpsc::Receiver<ShellRequest>,
}

impl Shell
where
    A: WindowAdapter,
{
    /// Creates a new application shell.
    pub fn new(requests: mpsc::Receiver<ShellRequest>) -> Self {
        Shell {
            window_shells: vec![],
            requests,
        }
    }

    /// Creates a window builder, that could be used to create a window and add it to the application shell.
    pub fn create_window(&mut self, adapter: A) -> WindowBuilder {
        WindowBuilder::new(self, adapter)
    }

    /// Creates a window builder from a settings object.
    pub fn create_window_from_settings(
        &mut self,
        settings: WindowSettings,
        adapter: A,
    ) -> WindowBuilder {
        WindowBuilder::from_settings(settings, self, adapter)
    }

    /// Receives window request from the application and handles them.
    pub fn receive_requests(&mut self) {
        let mut requests = vec![];
        for request in self.requests.try_iter() {
            requests.push(request);
        }

        for request in requests {
            match request {
                ShellRequest::CreateWindow(adapter, settings, window_requests) => {
                    self.create_window_from_settings(settings, adapter)
                        .request_receiver(window_requests)
                        .build();
                }
            }
        }
    }

    /// Runs (starts) the application shell and its windows.
    pub fn run(mut self) {
        window().request_animation_frame(move |_| {
            if self.window_shells.is_empty() {
                return;
            }

            for i in 0..self.window_shells.len() {
                let mut remove = false;
                if let Some(window_shell) = self.window_shells.get_mut(i) {
                    window_shell.render();
                    window_shell.update();
                    window_shell.drain_events();
                    window_shell.receive_requests();
                    if !window_shell.is_open() {
                        remove = true;
                    }
                }

                if remove {
                    self.window_shells.remove(i);
                    break;
                }
            }

            self.receive_requests();
            self.run();
        });
    }
}

lazy_static! {
    pub static ref CONSOLE: Console = Console;
}

pub struct Console;

impl Console {
    pub fn time(&self, _name: impl Into<String>) {
        // js! {
        //     console.time(@{&name.into()})
        // }
    }

    pub fn time_end(&self, _name: impl Into<String>) {
        // js! {
        //     console.timeEnd(@{&name.into()})
        // }
    }

    pub fn log(&self, message: impl Into<String>) {
        #[cfg(feature = "log")]
        js! {
            console.log(@{&message.into()});
        }
    }
}
<commit_msg>Removed unused import<commit_after>//! This module contains a platform specific implementation of the window shell.
use std::sync::mpsc;
use stdweb::{web::window};

use crate::prelude::*;

use self::states::*;
pub use self::window::*;
pub use self::window_builder::*;

mod states;
mod window;
mod window_builder;

fn set_panic_hook() {
    // When the `console_error_panic_hook` feature is enabled, we can call the
    // `set_panic_hook` function at least once during initialization, and then
    // we will get better error messages if our code ever panics.
    //
    // For more details see
    // https://github.com/rustwasm/console_error_panic_hook#readme
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

/// Initializes web stuff.
pub fn initialize() {
    set_panic_hook();
    stdweb::initialize();
}

/// Represents an application shell that could handle multiple windows.
pub struct Shell
where
    A: WindowAdapter,
{
    window_shells: Vec<Window>,
    requests: mpsc::Receiver<ShellRequest>,
}

impl Shell
where
    A: WindowAdapter,
{
    /// Creates a new application shell.
    pub fn new(requests: mpsc::Receiver<ShellRequest>) -> Self {
        Shell {
            window_shells: vec![],
            requests,
        }
    }

    /// Creates a window builder, that could be used to create a window and add it to the application shell.
    pub fn create_window(&mut self, adapter: A) -> WindowBuilder {
        WindowBuilder::new(self, adapter)
    }

    /// Creates a window builder from a settings object.
    pub fn create_window_from_settings(
        &mut self,
        settings: WindowSettings,
        adapter: A,
    ) -> WindowBuilder {
        WindowBuilder::from_settings(settings, self, adapter)
    }

    /// Receives window request from the application and handles them.
    pub fn receive_requests(&mut self) {
        let mut requests = vec![];
        for request in self.requests.try_iter() {
            requests.push(request);
        }

        for request in requests {
            match request {
                ShellRequest::CreateWindow(adapter, settings, window_requests) => {
                    self.create_window_from_settings(settings, adapter)
                        .request_receiver(window_requests)
                        .build();
                }
            }
        }
    }

    /// Runs (starts) the application shell and its windows.
    pub fn run(mut self) {
        window().request_animation_frame(move |_| {
            if self.window_shells.is_empty() {
                return;
            }

            for i in 0..self.window_shells.len() {
                let mut remove = false;
                if let Some(window_shell) = self.window_shells.get_mut(i) {
                    window_shell.render();
                    window_shell.update();
                    window_shell.drain_events();
                    window_shell.receive_requests();
                    if !window_shell.is_open() {
                        remove = true;
                    }
                }

                if remove {
                    self.window_shells.remove(i);
                    break;
                }
            }

            self.receive_requests();
            self.run();
        });
    }
}

lazy_static! {
    pub static ref CONSOLE: Console = Console;
}

pub struct Console;

impl Console {
    pub fn time(&self, _name: impl Into<String>) {
        // js! {
        //     console.time(@{&name.into()})
        // }
    }

    pub fn time_end(&self, _name: impl Into<String>) {
        // js! {
        //     console.timeEnd(@{&name.into()})
        // }
    }

    pub fn log(&self, message: impl Into<String>) {
        #[cfg(feature = "log")]
        js! {
            console.log(@{&message.into()});
        }
    }
}
<|endoftext|>


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

/// Get the executable path (as `OsString`).
#[macro_export]
macro_rules! executable_os(
    () => ({
        &std::env::args_os().next().unwrap()
    })
);

/// Get the executable path (as `String`; lossless).
#[macro_export]
macro_rules! executable(
    () => ({
        let exe = match executable_os!().to_str() {
            // * UTF-8
            Some(s) => s.to_string(),
            // * "lossless" debug format if `executable_os!()` is not well-formed UTF-8
            None => format!("{:?}", executable_os!())
        };
        &exe.to_owned()
    })
);

/// Get the executable name.
#[macro_export]
macro_rules! executable_name(
    () => ({
        &std::path::Path::new(executable_os!()).file_stem().unwrap().to_string_lossy()
    })
);

/// Derive the utility name.
#[macro_export]
macro_rules! util_name(
    () => ({
        let crate_name = env!("CARGO_PKG_NAME");
        if crate_name.starts_with("uu_") {
            &crate_name[3..]
        } else {
            &crate_name
        }
    })
);

//====

#[macro_export]
macro_rules! show(
    ($err:expr) => ({
        let e = $err;
        uucore::error::set_exit_code(e.code());
        eprintln!("{}: {}", executable_name!(), e);
    })
);

#[macro_export]
macro_rules! show_if_err(
    ($res:expr) => ({
        if let Err(e) = $res {
            show!(e);
        }
    })
);

/// Show an error to stderr in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", executable_name!());
        eprintln!($($args)+);
    })
);

/// Show a warning to stderr in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_error_custom_description (
    ($err:expr,$($args:tt)+) => ({
        eprint!("{}: {}: ", executable_name!(), $err);
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! show_warning(
    ($($args:tt)+) => ({
        eprint!("{}: warning: ", executable_name!());
        eprintln!($($args)+);
    })
);

/// Show a bad invocation help message in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_usage_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", executable_name!());
        eprintln!($($args)+);
        eprintln!("Try `{:?} --help` for more information.", executable!());
    })
);

//====

/// Calls `exit()` with the provided exit code.
#[macro_export]
macro_rules! exit(
    ($exit_code:expr) => ({
        ::std::process::exit($exit_code)
    })
);

/// Display the provided error message, then `exit()` with the provided exit code
#[macro_export]
macro_rules! crash(
    ($exit_code:expr, $($args:tt)+) => ({
        show_error!($($args)+);
        exit!($exit_code)
    })
);

/// Unwraps the Result. Instead of panicking, it exists the program with the
/// provided exit code.
#[macro_export]
macro_rules! crash_if_err(
    ($exit_code:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!($exit_code, "{}", f),
        }
    )
);

//====

/// Unwraps the Result. Instead of panicking, it shows the error and then
/// returns from the function with the provided exit code.
/// Assumes the current function returns an i32 value.
#[macro_export]
macro_rules! return_if_err(
    ($exit_code:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => {
                show_error!("{}", f);
                return $exit_code;
            }
        }
    )
);

//====

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!("{}", f)
        }
    )
);

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!("{}", f)
        }
    )
);

/// Unwraps the Result. Instead of panicking, it exists the program with exit
/// code 1.
#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!(1, "{}", f.to_string())
        }
    )
);

//-- message templates

//-- message templates : (join utility sub-macros)

#[macro_export]
macro_rules! snippet_list_join_oxford_comma {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
    );
}

#[macro_export]
macro_rules! snippet_list_join {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{} {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
    );
}

//-- message templates : invalid input

#[macro_export]
macro_rules! msg_invalid_input {
    ($reason: expr) => {
        format!("invalid input: {}", $reason)
    };
}

// -- message templates : invalid input : flag

#[macro_export]
macro_rules! msg_invalid_opt_use {
    ($about:expr, $flag:expr) => {
        msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
    };
    ($about:expr, $long_flag:expr, $short_flag:expr) => {
        msg_invalid_input!(format!(
            "The '{}' ('{}') option {}",
            $long_flag, $short_flag, $about
        ))
    };
}

#[macro_export]
macro_rules! msg_opt_only_usable_if {
    ($clause:expr, $flag:expr) => {
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
    };
    ($clause:expr, $long_flag:expr, $short_flag:expr) => {
        msg_invalid_opt_use!(
            format!("only usable if {}", $clause),
            $long_flag,
            $short_flag
        )
    };
}

#[macro_export]
macro_rules! msg_opt_invalid_should_be {
    ($expects:expr, $received:expr, $flag:expr) => {
        msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $flag
        )
    };
    ($expects:expr, $received:expr, $long_flag:expr, $short_flag:expr) => {
        msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $long_flag,
            $short_flag
        )
    };
}

// -- message templates : invalid input : input combinations

#[macro_export]
macro_rules! msg_expects_one_of {
    ($valOne:expr $(, $remaining_values:expr)*) => (
        msg_invalid_input!(format!("expects one of {}", snippet_list_join!("or", $valOne $(, $remaining_values)*)))
    );
}

#[macro_export]
macro_rules! msg_expects_no_more_than_one_of {
    ($valOne:expr $(, $remaining_values:expr)*) => (
        msg_invalid_input!(format!("expects no more than one of {}", snippet_list_join!("or", $valOne $(, $remaining_values)*))) ;
    );
}
<commit_msg>refactor/uucore ~ improve macro scope hygiene<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

/// Get the executable path (as `OsString`).
#[macro_export]
macro_rules! executable_os(
    () => ({
        &std::env::args_os().next().unwrap()
    })
);

/// Get the executable path (as `String`; lossless).
#[macro_export]
macro_rules! executable(
    () => ({
        let exe = match $crate::executable_os!().to_str() {
            // * UTF-8
            Some(s) => s.to_string(),
            // * "lossless" debug format if `executable_os!()` is not well-formed UTF-8
            None => format!("{:?}", $crate::executable_os!())
        };
        &exe.to_owned()
    })
);

/// Get the executable name.
#[macro_export]
macro_rules! executable_name(
    () => ({
        &std::path::Path::new($crate::executable_os!()).file_stem().unwrap().to_string_lossy()
    })
);

/// Derive the utility name.
#[macro_export]
macro_rules! util_name(
    () => ({
        let crate_name = env!("CARGO_PKG_NAME");
        if crate_name.starts_with("uu_") {
            &crate_name[3..]
        } else {
            &crate_name
        }
    })
);

//====

#[macro_export]
macro_rules! show(
    ($err:expr) => ({
        let e = $err;
        uucore::error::set_exit_code(e.code());
        eprintln!("{}: {}", $crate::executable_name!(), e);
    })
);

#[macro_export]
macro_rules! show_if_err(
    ($res:expr) => ({
        if let Err(e) = $res {
            show!(e);
        }
    })
);

/// Show an error to stderr in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", $crate::executable_name!());
        eprintln!($($args)+);
    })
);

/// Show a warning to stderr in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_error_custom_description (
    ($err:expr,$($args:tt)+) => ({
        eprint!("{}: {}: ", $crate::executable_name!(), $err);
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! show_warning(
    ($($args:tt)+) => ({
        eprint!("{}: warning: ", $crate::executable_name!());
        eprintln!($($args)+);
    })
);

/// Show a bad invocation help message in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_usage_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", $crate::executable_name!());
        eprintln!($($args)+);
        eprintln!("Try `{:?} --help` for more information.", $crate::executable!());
    })
);

//====

/// Calls `exit()` with the provided exit code.
#[macro_export]
macro_rules! exit(
    ($exit_code:expr) => ({
        ::std::process::exit($exit_code)
    })
);

/// Display the provided error message, then `exit()` with the provided exit code
#[macro_export]
macro_rules! crash(
    ($exit_code:expr, $($args:tt)+) => ({
        $crate::show_error!($($args)+);
        $crate::exit!($exit_code)
    })
);

/// Unwraps the Result. Instead of panicking, it exists the program with the
/// provided exit code.
#[macro_export]
macro_rules! crash_if_err(
    ($exit_code:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => $crate::crash!($exit_code, "{}", f),
        }
    )
);

//====

/// Unwraps the Result. Instead of panicking, it shows the error and then
/// returns from the function with the provided exit code.
/// Assumes the current function returns an i32 value.
#[macro_export]
macro_rules! return_if_err(
    ($exit_code:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => {
                $crate::show_error!("{}", f);
                return $exit_code;
            }
        }
    )
);

//====

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!("{}", f)
        }
    )
);

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!("{}", f)
        }
    )
);

/// Unwraps the Result. Instead of panicking, it exists the program with exit
/// code 1.
#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => $crate::crash!(1, "{}", f.to_string())
        }
    )
);

//-- message templates

//-- message templates : (join utility sub-macros)

#[macro_export]
macro_rules! snippet_list_join_oxford_comma {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
        format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
    );
}

#[macro_export]
macro_rules! snippet_list_join {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{} {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
        format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
    );
}

//-- message templates : invalid input

#[macro_export]
macro_rules! msg_invalid_input {
    ($reason: expr) => {
        format!("invalid input: {}", $reason)
    };
}

// -- message templates : invalid input : flag

#[macro_export]
macro_rules! msg_invalid_opt_use {
    ($about:expr, $flag:expr) => {
        $crate::msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
    };
    ($about:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_input!(format!(
            "The '{}' ('{}') option {}",
            $long_flag, $short_flag, $about
        ))
    };
}

#[macro_export]
macro_rules! msg_opt_only_usable_if {
    ($clause:expr, $flag:expr) => {
        $crate::msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
    };
    ($clause:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("only usable if {}", $clause),
            $long_flag,
            $short_flag
        )
    };
}

#[macro_export]
macro_rules! msg_opt_invalid_should_be {
    ($expects:expr, $received:expr, $flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $flag
        )
    };
    ($expects:expr, $received:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $long_flag,
            $short_flag
        )
    };
}

// -- message templates : invalid input : input combinations

#[macro_export]
macro_rules! msg_expects_one_of {
    ($valOne:expr $(, $remaining_values:expr)*) => (
        $crate::msg_invalid_input!(format!("expects one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*)))
    );
}

#[macro_export]
macro_rules! msg_expects_no_more_than_one_of {
    ($valOne:expr $(, $remaining_values:expr)*) => (
        $crate::msg_invalid_input!(format!("expects no more than one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*))) ;
    );
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::cell::RefCell;
use time::precise_time_ns;
use glfw;
use cgmath::vector::{Vector2};
use core::types::{Size2, MInt, Point2};
use core::conf::Config;
use core::fs::FileSystem;
use visualizer::mgl;
use visualizer::types::{MatId, ColorId, Time};
use visualizer::shader::Shader;
use visualizer::font_stash::FontStash;
use visualizer::context::Context;
use visualizer::state_visualizer::{
    StateVisualizer,
    StartGame,
    EndGame,
    QuitMenu,
};
use visualizer::game_state_visualizer::GameStateVisualizer;
use visualizer::menu_state_visualizer::MenuStateVisualizer;

type EventsReceiver = Receiver<(f64, glfw::WindowEvent)>;

pub struct Visualizer {
    visualizers: Vec<Box<StateVisualizer>>,
    dtime: Time,
    last_time: Time,
    glfw: glfw::Glfw,
    events: EventsReceiver,
    context: Context,
    fs: FileSystem,
    should_close: bool,
}

fn create_win(glfw: &glfw::Glfw, win_size: Size2<MInt>)
    -> (glfw::Window, EventsReceiver)
{
    let w = win_size.w as u32;
    let h = win_size.h as u32;
    let title = "Marauder";
    let flags = glfw::Windowed;
    glfw.create_window(w, h, title, flags).unwrap()
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let fs = FileSystem::new();
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
        let config = Config::new(&fs.get(&Path::new("data/conf_visualizer.json")));
        let win_size = config.get::<Size2<MInt>>("screen_size");
        let (win, events) = create_win(&glfw, win_size);
        glfw.make_context_current(Some(&win));
        mgl::load_gl_funcs_with(|procname| glfw.get_proc_address(procname));
        mgl::init_opengl();
        win.set_all_polling(true);
        let font_size = config.get("font_size");
        let font_stash = FontStash::new(
            &fs.get(&Path::new("data/DroidSerif-Regular.ttf")), font_size);
        let shader = Shader::new(
            &fs.get(&Path::new("data/normal.vs.glsl")),
            &fs.get(&Path::new("data/normal.fs.glsl")),
        );
        let mvp_mat_id = MatId{id: shader.get_uniform("mvp_mat")};
        let basic_color_id = ColorId{id: shader.get_uniform("basic_color")};
        let context = Context {
            win: win,
            win_size: win_size,
            config: config,
            mouse_pos: Point2{v: Vector2::zero()},
            font_stash: RefCell::new(font_stash),
            shader: shader,
            mvp_mat_id: mvp_mat_id,
            basic_color_id: basic_color_id,
        };
        let visualizer = box MenuStateVisualizer::new(&context);
        Visualizer {
            visualizers: vec![visualizer as Box<StateVisualizer>],
            dtime: Time{n: 0},
            last_time: Time{n: precise_time_ns()},
            glfw: glfw,
            events: events,
            context: context,
            fs: fs,
            should_close: false,
        }
    }

    fn get_events(&mut self) -> Vec<glfw::WindowEvent> {
        self.glfw.poll_events();
        let mut events = Vec::new();
        for (_, event) in glfw::flush_messages(&self.events) {
            events.push(event);
        }
        events
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    // TODO: simplify
    pub fn tick(&mut self) {
        {
            let events = self.get_events();
            let visualizer = self.visualizers.mut_last().unwrap(); // TODO: remove unwrap
            for event in events.iter() {
                visualizer.handle_event(&self.context, *event);
                self.context.handle_event(*event);
            }
            visualizer.logic();
            visualizer.draw(&self.context, self.dtime);
        }
        let cmd = self.visualizers.last().unwrap().get_command(); // TODO: remove unwrap
        match cmd {
            Some(StartGame) => {
                let visualizer = box GameStateVisualizer::new(
                    &self.fs, &self.context);
                self.visualizers.push(visualizer as Box<StateVisualizer>);
            }
            Some(EndGame) => {
                self.visualizers.pop();
            },
            Some(QuitMenu) => {
                self.should_close = true;
            },
            None => {},
        }
        self.update_time();
    }

    pub fn update_time(&mut self) {
        let time = precise_time_ns();
        self.dtime.n = time - self.last_time.n;
        self.last_time.n = time;
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Visualizer: Simplified tick()<commit_after>// See LICENSE file for copyright and license details.

use std::cell::RefCell;
use time::precise_time_ns;
use glfw;
use cgmath::vector::{Vector2};
use core::types::{Size2, MInt, Point2};
use core::conf::Config;
use core::fs::FileSystem;
use visualizer::mgl;
use visualizer::types::{MatId, ColorId, Time};
use visualizer::shader::Shader;
use visualizer::font_stash::FontStash;
use visualizer::context::Context;
use visualizer::state_visualizer::{
    StateVisualizer,
    StartGame,
    EndGame,
    QuitMenu,
};
use visualizer::game_state_visualizer::GameStateVisualizer;
use visualizer::menu_state_visualizer::MenuStateVisualizer;

type EventsReceiver = Receiver<(f64, glfw::WindowEvent)>;

pub struct Visualizer {
    visualizers: Vec<Box<StateVisualizer>>,
    dtime: Time,
    last_time: Time,
    glfw: glfw::Glfw,
    events: EventsReceiver,
    context: Context,
    fs: FileSystem,
    should_close: bool,
}

fn create_win(glfw: &glfw::Glfw, win_size: Size2<MInt>)
    -> (glfw::Window, EventsReceiver)
{
    let w = win_size.w as u32;
    let h = win_size.h as u32;
    let title = "Marauder";
    let flags = glfw::Windowed;
    glfw.create_window(w, h, title, flags).unwrap()
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let fs = FileSystem::new();
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
        let config = Config::new(&fs.get(&Path::new("data/conf_visualizer.json")));
        let win_size = config.get::<Size2<MInt>>("screen_size");
        let (win, events) = create_win(&glfw, win_size);
        glfw.make_context_current(Some(&win));
        mgl::load_gl_funcs_with(|procname| glfw.get_proc_address(procname));
        mgl::init_opengl();
        win.set_all_polling(true);
        let font_size = config.get("font_size");
        let font_stash = FontStash::new(
            &fs.get(&Path::new("data/DroidSerif-Regular.ttf")), font_size);
        let shader = Shader::new(
            &fs.get(&Path::new("data/normal.vs.glsl")),
            &fs.get(&Path::new("data/normal.fs.glsl")),
        );
        let mvp_mat_id = MatId{id: shader.get_uniform("mvp_mat")};
        let basic_color_id = ColorId{id: shader.get_uniform("basic_color")};
        let context = Context {
            win: win,
            win_size: win_size,
            config: config,
            mouse_pos: Point2{v: Vector2::zero()},
            font_stash: RefCell::new(font_stash),
            shader: shader,
            mvp_mat_id: mvp_mat_id,
            basic_color_id: basic_color_id,
        };
        let visualizer = box MenuStateVisualizer::new(&context);
        Visualizer {
            visualizers: vec![visualizer as Box<StateVisualizer>],
            dtime: Time{n: 0},
            last_time: Time{n: precise_time_ns()},
            glfw: glfw,
            events: events,
            context: context,
            fs: fs,
            should_close: false,
        }
    }

    fn get_events(&mut self) -> Vec<glfw::WindowEvent> {
        self.glfw.poll_events();
        let mut events = Vec::new();
        for (_, event) in glfw::flush_messages(&self.events) {
            events.push(event);
        }
        events
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_cmd(&mut self) {
        let cmd = match self.visualizers.last() {
            Some(visualizer) => visualizer.get_command(),
            None => fail!("No state visualizer"),
        };
        match cmd {
            Some(StartGame) => {
                let visualizer = box GameStateVisualizer::new(
                    &self.fs, &self.context);
                self.visualizers.push(visualizer as Box<StateVisualizer>);
            }
            Some(EndGame) => {
                self.visualizers.pop();
            },
            Some(QuitMenu) => {
                self.should_close = true;
            },
            None => {},
        }
    }

    // TODO: simplify
    pub fn tick(&mut self) {
        {
            let events = self.get_events();
            let visualizer = match self.visualizers.mut_last() {
                Some(visualizer) => visualizer,
                None => fail!("No state visualizer"),
            };
            for event in events.iter() {
                visualizer.handle_event(&self.context, *event);
                self.context.handle_event(*event);
            }
            visualizer.logic();
            visualizer.draw(&self.context, self.dtime);
        }
        self.handle_cmd();
        self.update_time();
    }

    pub fn update_time(&mut self) {
        let time = precise_time_ns();
        self.dtime.n = time - self.last_time.n;
        self.last_time.n = time;
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::CString;
use syntax::feature_gate::UnstableFeatures;

use std::str;
use std::slice;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let n_args = sess.opts.cg.llvm_args.len();
    let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
    let mut llvm_args = Vec::with_capacity(n_args + 1);

    llvm::LLVMRustInstallFatalErrorHandler();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
        if sess.opts.debugging_opts.disable_instrumentation_preinliner {
            add("-disable-preinline");
        }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    ::rustc_llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.

const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
    ("aclass", Some("arm_target_feature")),
    ("mclass", Some("arm_target_feature")),
    ("rclass", Some("arm_target_feature")),
    ("dsp", Some("arm_target_feature")),
    ("neon", Some("arm_target_feature")),
    ("v5te", Some("arm_target_feature")),
    ("v6k", Some("arm_target_feature")),
    ("v6t2", Some("arm_target_feature")),
    ("v7", Some("arm_target_feature")),
    ("vfp2", Some("arm_target_feature")),
    ("vfp3", Some("arm_target_feature")),
    ("vfp4", Some("arm_target_feature")),
];

const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
    ("fp", Some("aarch64_target_feature")),
    ("neon", Some("aarch64_target_feature")),
    ("sve", Some("aarch64_target_feature")),
    ("crc", Some("aarch64_target_feature")),
    ("crypto", Some("aarch64_target_feature")),
    ("ras", Some("aarch64_target_feature")),
    ("lse", Some("aarch64_target_feature")),
    ("rdm", Some("aarch64_target_feature")),
    ("fp16", Some("aarch64_target_feature")),
    ("rcpc", Some("aarch64_target_feature")),
    ("dotprod", Some("aarch64_target_feature")),
    ("v8.1a", Some("aarch64_target_feature")),
    ("v8.2a", Some("aarch64_target_feature")),
    ("v8.3a", Some("aarch64_target_feature")),
];

const X86_WHITELIST: &[(&str, Option<&str>)] = &[
    ("aes", None),
    ("avx", None),
    ("avx2", None),
    ("avx512bw", Some("avx512_target_feature")),
    ("avx512cd", Some("avx512_target_feature")),
    ("avx512dq", Some("avx512_target_feature")),
    ("avx512er", Some("avx512_target_feature")),
    ("avx512f", Some("avx512_target_feature")),
    ("avx512ifma", Some("avx512_target_feature")),
    ("avx512pf", Some("avx512_target_feature")),
    ("avx512vbmi", Some("avx512_target_feature")),
    ("avx512vl", Some("avx512_target_feature")),
    ("avx512vpopcntdq", Some("avx512_target_feature")),
    ("bmi1", None),
    ("bmi2", None),
    ("fma", None),
    ("fxsr", None),
    ("lzcnt", None),
    ("mmx", Some("mmx_target_feature")),
    ("pclmulqdq", None),
    ("popcnt", None),
    ("rdrand", None),
    ("rdseed", None),
    ("sha", None),
    ("sse", None),
    ("sse2", None),
    ("sse3", None),
    ("sse4.1", None),
    ("sse4.2", None),
    ("sse4a", Some("sse4a_target_feature")),
    ("ssse3", None),
    ("tbm", Some("tbm_target_feature")),
    ("xsave", None),
    ("xsavec", None),
    ("xsaveopt", None),
    ("xsaves", None),
];

const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
    ("hvx", Some("hexagon_target_feature")),
    ("hvx-double", Some("hexagon_target_feature")),
];

const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
    ("altivec", Some("powerpc_target_feature")),
    ("power8-altivec", Some("powerpc_target_feature")),
    ("power9-altivec", Some("powerpc_target_feature")),
    ("power8-vector", Some("powerpc_target_feature")),
    ("power9-vector", Some("powerpc_target_feature")),
    ("vsx", Some("powerpc_target_feature")),
];

const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
    ("fp64", Some("mips_target_feature")),
    ("msa", Some("mips_target_feature")),
];

const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
    ("simd128", Some("wasm_target_feature")),
    ("atomics", Some("wasm_target_feature")),
];

/// When rustdoc is running, provide a list of all known features so that all their respective
/// primtives may be documented.
///
/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
/// iterator!
pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
    ARM_WHITELIST.iter().cloned()
        .chain(AARCH64_WHITELIST.iter().cloned())
        .chain(X86_WHITELIST.iter().cloned())
        .chain(HEXAGON_WHITELIST.iter().cloned())
        .chain(POWERPC_WHITELIST.iter().cloned())
        .chain(MIPS_WHITELIST.iter().cloned())
        .chain(WASM_WHITELIST.iter().cloned())
}

pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
    let arch = if sess.target.target.arch == "x86_64" {
        "x86"
    } else {
        &*sess.target.target.arch
    };
    match (arch, s) {
        ("x86", "pclmulqdq") => "pclmul",
        ("x86", "rdrand") => "rdrnd",
        ("x86", "bmi1") => "bmi",
        ("aarch64", "fp") => "fp-armv8",
        ("aarch64", "fp16") => "fullfp16",
        (_, s) => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess, true);
    target_feature_whitelist(sess)
        .iter()
        .filter_map(|&(feature, gate)| {
            if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
                Some(feature)
            } else {
                None
            }
        })
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(sess, feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature)).collect()
}

pub fn target_feature_whitelist(sess: &Session)
    -> &'static [(&'static str, Option<&'static str>)]
{
    match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        "wasm32" => WASM_WHITELIST,
        _ => &[],
    }
}

pub fn print_version() {
    // Can be called without initializing LLVM
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_target_machine(sess, true);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
        }
    }
}

pub fn target_cpu(sess: &Session) -> &str {
    let name = match sess.opts.cg.target_cpu {
        Some(ref s) => &**s,
        None => &*sess.target.target.options.cpu
    };
    if name != "native" {
        return name
    }

    unsafe {
        let mut len = 0;
        let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
        str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
    }
}
<commit_msg>Disable wasm32 features on emscripten<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::CString;
use syntax::feature_gate::UnstableFeatures;

use std::str;
use std::slice;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let n_args = sess.opts.cg.llvm_args.len();
    let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
    let mut llvm_args = Vec::with_capacity(n_args + 1);

    llvm::LLVMRustInstallFatalErrorHandler();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
        if sess.opts.debugging_opts.disable_instrumentation_preinliner {
            add("-disable-preinline");
        }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    ::rustc_llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.

const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
    ("aclass", Some("arm_target_feature")),
    ("mclass", Some("arm_target_feature")),
    ("rclass", Some("arm_target_feature")),
    ("dsp", Some("arm_target_feature")),
    ("neon", Some("arm_target_feature")),
    ("v5te", Some("arm_target_feature")),
    ("v6k", Some("arm_target_feature")),
    ("v6t2", Some("arm_target_feature")),
    ("v7", Some("arm_target_feature")),
    ("vfp2", Some("arm_target_feature")),
    ("vfp3", Some("arm_target_feature")),
    ("vfp4", Some("arm_target_feature")),
];

const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
    ("fp", Some("aarch64_target_feature")),
    ("neon", Some("aarch64_target_feature")),
    ("sve", Some("aarch64_target_feature")),
    ("crc", Some("aarch64_target_feature")),
    ("crypto", Some("aarch64_target_feature")),
    ("ras", Some("aarch64_target_feature")),
    ("lse", Some("aarch64_target_feature")),
    ("rdm", Some("aarch64_target_feature")),
    ("fp16", Some("aarch64_target_feature")),
    ("rcpc", Some("aarch64_target_feature")),
    ("dotprod", Some("aarch64_target_feature")),
    ("v8.1a", Some("aarch64_target_feature")),
    ("v8.2a", Some("aarch64_target_feature")),
    ("v8.3a", Some("aarch64_target_feature")),
];

const X86_WHITELIST: &[(&str, Option<&str>)] = &[
    ("aes", None),
    ("avx", None),
    ("avx2", None),
    ("avx512bw", Some("avx512_target_feature")),
    ("avx512cd", Some("avx512_target_feature")),
    ("avx512dq", Some("avx512_target_feature")),
    ("avx512er", Some("avx512_target_feature")),
    ("avx512f", Some("avx512_target_feature")),
    ("avx512ifma", Some("avx512_target_feature")),
    ("avx512pf", Some("avx512_target_feature")),
    ("avx512vbmi", Some("avx512_target_feature")),
    ("avx512vl", Some("avx512_target_feature")),
    ("avx512vpopcntdq", Some("avx512_target_feature")),
    ("bmi1", None),
    ("bmi2", None),
    ("fma", None),
    ("fxsr", None),
    ("lzcnt", None),
    ("mmx", Some("mmx_target_feature")),
    ("pclmulqdq", None),
    ("popcnt", None),
    ("rdrand", None),
    ("rdseed", None),
    ("sha", None),
    ("sse", None),
    ("sse2", None),
    ("sse3", None),
    ("sse4.1", None),
    ("sse4.2", None),
    ("sse4a", Some("sse4a_target_feature")),
    ("ssse3", None),
    ("tbm", Some("tbm_target_feature")),
    ("xsave", None),
    ("xsavec", None),
    ("xsaveopt", None),
    ("xsaves", None),
];

const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
    ("hvx", Some("hexagon_target_feature")),
    ("hvx-double", Some("hexagon_target_feature")),
];

const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
    ("altivec", Some("powerpc_target_feature")),
    ("power8-altivec", Some("powerpc_target_feature")),
    ("power9-altivec", Some("powerpc_target_feature")),
    ("power8-vector", Some("powerpc_target_feature")),
    ("power9-vector", Some("powerpc_target_feature")),
    ("vsx", Some("powerpc_target_feature")),
];

const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
    ("fp64", Some("mips_target_feature")),
    ("msa", Some("mips_target_feature")),
];

const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
    ("simd128", Some("wasm_target_feature")),
    ("atomics", Some("wasm_target_feature")),
];

/// When rustdoc is running, provide a list of all known features so that all their respective
/// primtives may be documented.
///
/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
/// iterator!
pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
    ARM_WHITELIST.iter().cloned()
        .chain(AARCH64_WHITELIST.iter().cloned())
        .chain(X86_WHITELIST.iter().cloned())
        .chain(HEXAGON_WHITELIST.iter().cloned())
        .chain(POWERPC_WHITELIST.iter().cloned())
        .chain(MIPS_WHITELIST.iter().cloned())
        .chain(WASM_WHITELIST.iter().cloned())
}

pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
    let arch = if sess.target.target.arch == "x86_64" {
        "x86"
    } else {
        &*sess.target.target.arch
    };
    match (arch, s) {
        ("x86", "pclmulqdq") => "pclmul",
        ("x86", "rdrand") => "rdrnd",
        ("x86", "bmi1") => "bmi",
        ("aarch64", "fp") => "fp-armv8",
        ("aarch64", "fp16") => "fullfp16",
        (_, s) => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess, true);
    target_feature_whitelist(sess)
        .iter()
        .filter_map(|&(feature, gate)| {
            if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
                Some(feature)
            } else {
                None
            }
        })
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(sess, feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature)).collect()
}

pub fn target_feature_whitelist(sess: &Session)
    -> &'static [(&'static str, Option<&'static str>)]
{
    match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        // wasm32 on emscripten does not support these target features
        "wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST,
        _ => &[],
    }
}

pub fn print_version() {
    // Can be called without initializing LLVM
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_target_machine(sess, true);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
        }
    }
}

pub fn target_cpu(sess: &Session) -> &str {
    let name = match sess.opts.cg.target_cpu {
        Some(ref s) => &**s,
        None => &*sess.target.target.options.cpu
    };
    if name != "native" {
        return name
    }

    unsafe {
        let mut len = 0;
        let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
        str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use encoder::EncodeContext;
use index::IndexData;
use rbml::writer::Encoder;
use rustc::dep_graph::{DepGraph, DepNode, DepTask};
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc_data_structures::fnv::FnvHashMap;

pub struct IndexBuilder<'a, 'tcx> {
    dep_graph: &'a DepGraph,
    items: IndexData,
    xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
}

/// "interned" entries referenced by id
#[derive(PartialEq, Eq, Hash)]
pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }

impl<'a, 'tcx> IndexBuilder<'a, 'tcx> {
    pub fn new(ecx: &EncodeContext<'a, 'tcx>) -> Self {
        IndexBuilder {
            dep_graph: &ecx.tcx.dep_graph,
            items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
            xrefs: FnvHashMap()
        }
    }

    /// Records that `id` is being emitted at the current offset.
    /// This data is later used to construct the item index in the
    /// metadata so we can quickly find the data for a given item.
    ///
    /// Returns a dep-graph task that you should keep live as long as
    /// the data for this item is being emitted.
    pub fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> {
        let position = rbml_w.mark_stable_position();
        self.items.record(id, position);
        self.dep_graph.in_task(DepNode::MetaData(id))
    }

    pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
        let old_len = self.xrefs.len() as u32;
        *self.xrefs.entry(xref).or_insert(old_len)
    }

    pub fn into_fields(self) -> (IndexData, FnvHashMap<XRef<'tcx>, u32>) {
        (self.items, self.xrefs)
    }
}

<commit_msg>store ecx, not dep-graph<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use encoder::EncodeContext;
use index::IndexData;
use rbml::writer::Encoder;
use rustc::dep_graph::{DepGraph, DepNode, DepTask};
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc_data_structures::fnv::FnvHashMap;

pub struct IndexBuilder<'a, 'tcx> {
    ecx: &'a EncodeContext<'a, 'tcx>,
    items: IndexData,
    xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
}

/// "interned" entries referenced by id
#[derive(PartialEq, Eq, Hash)]
pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }

impl<'a, 'tcx> IndexBuilder<'a, 'tcx> {
    pub fn new(ecx: &EncodeContext<'a, 'tcx>) -> Self {
        IndexBuilder {
            ecx: ecx,
            items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
            xrefs: FnvHashMap()
        }
    }

    pub fn ecx(&self) {
        self.ecx
    }

    /// Records that `id` is being emitted at the current offset.
    /// This data is later used to construct the item index in the
    /// metadata so we can quickly find the data for a given item.
    ///
    /// Returns a dep-graph task that you should keep live as long as
    /// the data for this item is being emitted.
    pub fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> {
        let position = rbml_w.mark_stable_position();
        self.items.record(id, position);
        self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id))
    }

    pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
        let old_len = self.xrefs.len() as u32;
        *self.xrefs.entry(xref).or_insert(old_len)
    }

    pub fn into_fields(self) -> (IndexData, FnvHashMap<XRef<'tcx>, u32>) {
        (self.items, self.xrefs)
    }
}

<|endoftext|>


<commit_before>//! Attributes & documentation for hir types.
use hir_def::{
    attr::{Attrs, Documentation},
    path::ModPath,
    resolver::HasResolver,
    AttrDefId, GenericParamId, ModuleDefId,
};
use hir_expand::hygiene::Hygiene;
use hir_ty::db::HirDatabase;
use syntax::ast;

use crate::{
    Adt, Const, Enum, Field, Function, GenericParam, MacroDef, Module, ModuleDef, Static, Struct,
    Trait, TypeAlias, Union, Variant,
};

pub trait HasAttrs {
    fn attrs(self, db: &dyn HirDatabase) -> Attrs;
    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
    fn resolve_doc_path(
        self,
        db: &dyn HirDatabase,
        link: &str,
        ns: Option<Namespace>,
    ) -> Option<ModuleDef>;
}

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum Namespace {
    Types,
    Values,
    Macros,
}

macro_rules! impl_has_attrs {
    ($(($def:ident, $def_id:ident),)*) => {$(
        impl HasAttrs for $def {
            fn attrs(self, db: &dyn HirDatabase) -> Attrs {
                let def = AttrDefId::$def_id(self.into());
                db.attrs(def)
            }
            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                let def = AttrDefId::$def_id(self.into());
                db.attrs(def).docs()
            }
            fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> {
                let def = AttrDefId::$def_id(self.into());
                resolve_doc_path(db, def, link, ns).map(ModuleDef::from)
            }
        }
    )*};
}

impl_has_attrs![
    (Field, FieldId),
    (Variant, EnumVariantId),
    (Static, StaticId),
    (Const, ConstId),
    (Trait, TraitId),
    (TypeAlias, TypeAliasId),
    (MacroDef, MacroDefId),
    (Function, FunctionId),
    (Adt, AdtId),
    (Module, ModuleId),
    (GenericParam, GenericParamId),
];

macro_rules! impl_has_attrs_adt {
    ($($adt:ident),*) => {$(
        impl HasAttrs for $adt {
            fn attrs(self, db: &dyn HirDatabase) -> Attrs {
                Adt::$adt(self).attrs(db)
            }
            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                Adt::$adt(self).docs(db)
            }
            fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> {
                Adt::$adt(self).resolve_doc_path(db, link, ns)
            }
        }
    )*};
}

impl_has_attrs_adt![Struct, Union, Enum];

fn resolve_doc_path(
    db: &dyn HirDatabase,
    def: AttrDefId,
    link: &str,
    ns: Option<Namespace>,
) -> Option<ModuleDefId> {
    let resolver = match def {
        AttrDefId::ModuleId(it) => it.resolver(db.upcast()),
        AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()),
        AttrDefId::AdtId(it) => it.resolver(db.upcast()),
        AttrDefId::FunctionId(it) => it.resolver(db.upcast()),
        AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()),
        AttrDefId::StaticId(it) => it.resolver(db.upcast()),
        AttrDefId::ConstId(it) => it.resolver(db.upcast()),
        AttrDefId::TraitId(it) => it.resolver(db.upcast()),
        AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
        AttrDefId::ImplId(it) => it.resolver(db.upcast()),
        AttrDefId::GenericParamId(it) => match it {
            GenericParamId::TypeParamId(it) => it.parent,
            GenericParamId::LifetimeParamId(it) => it.parent,
            GenericParamId::ConstParamId(it) => it.parent,
        }
        .resolver(db.upcast()),
        AttrDefId::MacroDefId(_) => return None,
    };
    let path = ast::Path::parse(link).ok()?;
    let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();
    let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
    let def = match ns {
        Some(Namespace::Types) => resolved.take_types()?,
        Some(Namespace::Values) => resolved.take_values()?,
        Some(Namespace::Macros) => return None,
        None => resolved.iter_items().find_map(|it| it.as_module_def_id())?,
    };
    Some(def.into())
}
<commit_msg>Implement HasAttrs for Type-, Const- and LifetimeParam<commit_after>//! Attributes & documentation for hir types.
use hir_def::{
    attr::{Attrs, Documentation},
    path::ModPath,
    resolver::HasResolver,
    AttrDefId, GenericParamId, ModuleDefId,
};
use hir_expand::hygiene::Hygiene;
use hir_ty::db::HirDatabase;
use syntax::ast;

use crate::{
    Adt, Const, ConstParam, Enum, Field, Function, GenericParam, LifetimeParam, MacroDef, Module,
    ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
};

pub trait HasAttrs {
    fn attrs(self, db: &dyn HirDatabase) -> Attrs;
    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
    fn resolve_doc_path(
        self,
        db: &dyn HirDatabase,
        link: &str,
        ns: Option<Namespace>,
    ) -> Option<ModuleDef>;
}

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum Namespace {
    Types,
    Values,
    Macros,
}

macro_rules! impl_has_attrs {
    ($(($def:ident, $def_id:ident),)*) => {$(
        impl HasAttrs for $def {
            fn attrs(self, db: &dyn HirDatabase) -> Attrs {
                let def = AttrDefId::$def_id(self.into());
                db.attrs(def)
            }
            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                let def = AttrDefId::$def_id(self.into());
                db.attrs(def).docs()
            }
            fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> {
                let def = AttrDefId::$def_id(self.into());
                resolve_doc_path(db, def, link, ns).map(ModuleDef::from)
            }
        }
    )*};
}

impl_has_attrs![
    (Field, FieldId),
    (Variant, EnumVariantId),
    (Static, StaticId),
    (Const, ConstId),
    (Trait, TraitId),
    (TypeAlias, TypeAliasId),
    (MacroDef, MacroDefId),
    (Function, FunctionId),
    (Adt, AdtId),
    (Module, ModuleId),
    (GenericParam, GenericParamId),
];

macro_rules! impl_has_attrs_enum {
    ($($variant:ident),* for $enum:ident) => {$(
        impl HasAttrs for $variant {
            fn attrs(self, db: &dyn HirDatabase) -> Attrs {
                $enum::$variant(self).attrs(db)
            }
            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                $enum::$variant(self).docs(db)
            }
            fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> {
                $enum::$variant(self).resolve_doc_path(db, link, ns)
            }
        }
    )*};
}

impl_has_attrs_enum![Struct, Union, Enum for Adt];
impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam];

fn resolve_doc_path(
    db: &dyn HirDatabase,
    def: AttrDefId,
    link: &str,
    ns: Option<Namespace>,
) -> Option<ModuleDefId> {
    let resolver = match def {
        AttrDefId::ModuleId(it) => it.resolver(db.upcast()),
        AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()),
        AttrDefId::AdtId(it) => it.resolver(db.upcast()),
        AttrDefId::FunctionId(it) => it.resolver(db.upcast()),
        AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()),
        AttrDefId::StaticId(it) => it.resolver(db.upcast()),
        AttrDefId::ConstId(it) => it.resolver(db.upcast()),
        AttrDefId::TraitId(it) => it.resolver(db.upcast()),
        AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
        AttrDefId::ImplId(it) => it.resolver(db.upcast()),
        AttrDefId::GenericParamId(it) => match it {
            GenericParamId::TypeParamId(it) => it.parent,
            GenericParamId::LifetimeParamId(it) => it.parent,
            GenericParamId::ConstParamId(it) => it.parent,
        }
        .resolver(db.upcast()),
        AttrDefId::MacroDefId(_) => return None,
    };
    let path = ast::Path::parse(link).ok()?;
    let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();
    let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
    let def = match ns {
        Some(Namespace::Types) => resolved.take_types()?,
        Some(Namespace::Values) => resolved.take_values()?,
        Some(Namespace::Macros) => return None,
        None => resolved.iter_items().find_map(|it| it.as_module_def_id())?,
    };
    Some(def.into())
}
<|endoftext|>


<commit_before>use std::{
    fs,
    path::{Path, PathBuf},
    sync::{mpsc, Arc},
    time::Duration,
    thread,
};
use crossbeam_channel::{Sender, Receiver, unbounded, RecvError, select};
use relative_path::RelativePathBuf;
use walkdir::WalkDir;
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as _Watcher};

use crate::{Roots, VfsRoot, VfsTask};

pub(crate) enum Task {
    AddRoot { root: VfsRoot },
}

/// `TaskResult` transfers files read on the IO thread to the VFS on the main
/// thread.
#[derive(Debug)]
pub(crate) enum TaskResult {
    /// Emitted when we've recursively scanned a source root during the initial
    /// load.
    BulkLoadRoot { root: VfsRoot, files: Vec<(RelativePathBuf, String)> },
    /// Emitted when we've noticed that a single file has changed.
    ///
    /// Note that this by design does not distinguish between
    /// create/delete/write events, and instead specifies the *current* state of
    /// the file. The idea is to guarantee that in the quiescent state the sum
    /// of all results equals to the current state of the file system, while
    /// allowing to skip intermediate events in non-quiescent states.
    SingleFile { root: VfsRoot, path: RelativePathBuf, text: Option<String> },
}

/// The kind of raw notification we've received from the notify library.
///
/// Note that these are not necessary 100% precise (for example we might receive
/// `Create` instead of `Write`, see #734), but we try do distinguish `Create`s
/// to implement recursive watching of directories.
#[derive(Debug)]
enum ChangeKind {
    Create,
    Write,
    Remove,
}

const WATCHER_DELAY: Duration = Duration::from_millis(250);

// Like thread::JoinHandle, but joins the thread on drop.
//
// This is useful because it guarantees the absence of run-away threads, even if
// code panics. This is important, because we might seem panics in the test and
// we might be used in an IDE context, where a failed component is just
// restarted.
//
// Because all threads are joined, care must be taken to avoid deadlocks. That
// typically means ensuring that channels are dropped before the threads.
struct ScopedThread(Option<thread::JoinHandle<()>>);

impl ScopedThread {
    fn spawn(name: String, f: impl FnOnce() + Send + 'static) -> ScopedThread {
        let handle = thread::Builder::new().name(name).spawn(f).unwrap();
        ScopedThread(Some(handle))
    }
}

impl Drop for ScopedThread {
    fn drop(&mut self) {
        let res = self.0.take().unwrap().join();
        if !thread::panicking() {
            res.unwrap();
        }
    }
}

pub(crate) struct Worker {
    // XXX: it's important to drop `sender` before `_thread` to avoid deadlock.
    pub(crate) sender: Sender<Task>,
    _thread: ScopedThread,
    pub(crate) receiver: Receiver<VfsTask>,
}

pub(crate) fn start(roots: Arc<Roots>) -> Worker {
    // This is a pretty elaborate setup of threads & channels! It is
    // explained by the following concerns:
    //    * we need to burn a thread translating from notify's mpsc to
    //      crossbeam_channel.
    //    * we want to read all files from a single thread, to guarantee that
    //      we always get fresher versions and never go back in time.
    //    * we want to tear down everything neatly during shutdown.
    let _thread;
    // This are the channels we use to communicate with outside world.
    // If `input_receiver` is closed we need to tear ourselves down.
    // `output_sender` should not be closed unless the parent died.
    let (input_sender, input_receiver) = unbounded();
    let (output_sender, output_receiver) = unbounded();

    _thread = ScopedThread::spawn("vfs".to_string(), move || {
        // Make sure that the destruction order is
        //
        // * notify_sender
        // * _thread
        // * watcher_sender
        //
        // this is required to avoid deadlocks.

        // These are the corresponding crossbeam channels
        let (watcher_sender, watcher_receiver) = unbounded();
        let _notify_thread;
        {
            // These are `std` channels notify will send events to
            let (notify_sender, notify_receiver) = mpsc::channel();

            let mut watcher = notify::watcher(notify_sender, WATCHER_DELAY)
                .map_err(|e| log::error!("failed to spawn notify {}", e))
                .ok();
            // Start a silly thread to transform between two channels
            _notify_thread = ScopedThread::spawn("notify-convertor".to_string(), move || {
                notify_receiver
                    .into_iter()
                    .for_each(|event| convert_notify_event(event, &watcher_sender))
            });

            // Process requests from the called or notifications from
            // watcher until the caller says stop.
            loop {
                select! {
                    // Received request from the caller. If this channel is
                    // closed, we should shutdown everything.
                    recv(input_receiver) -> t => match t {
                        Err(RecvError) => {
                            drop(input_receiver);
                            break
                        },
                        Ok(Task::AddRoot { root }) => {
                            watch_root(watcher.as_mut(), &output_sender, &*roots, root);
                        }
                    },
                    // Watcher send us changes. If **this** channel is
                    // closed, the watcher has died, which indicates a bug
                    // -- escalate!
                    recv(watcher_receiver) -> event => match event {
                        Err(RecvError) => panic!("watcher is dead"),
                        Ok((path, change)) => {
                            handle_change(watcher.as_mut(), &output_sender, &*roots, path, change);
                        }
                    },
                }
            }
        }
        // Drain pending events: we are not interested in them anyways!
        watcher_receiver.into_iter().for_each(|_| ());
    });
    Worker { sender: input_sender, _thread, receiver: output_receiver }
}

fn watch_root(
    watcher: Option<&mut RecommendedWatcher>,
    sender: &Sender<VfsTask>,
    roots: &Roots,
    root: VfsRoot,
) {
    let root_path = roots.path(root);
    log::debug!("loading {} ...", root_path.display());
    let files = watch_recursive(watcher, root_path, roots, root)
        .into_iter()
        .filter_map(|path| {
            let abs_path = path.to_path(&root_path);
            let text = read_to_string(&abs_path)?;
            Some((path, text))
        })
        .collect();
    let res = TaskResult::BulkLoadRoot { root, files };
    sender.send(VfsTask(res)).unwrap();
    log::debug!("... loaded {}", root_path.display());
}

fn convert_notify_event(event: DebouncedEvent, sender: &Sender<(PathBuf, ChangeKind)>) {
    // forward relevant events only
    match event {
        DebouncedEvent::NoticeWrite(_)
        | DebouncedEvent::NoticeRemove(_)
        | DebouncedEvent::Chmod(_) => {
            // ignore
        }
        DebouncedEvent::Rescan => {
            // TODO: rescan all roots
        }
        DebouncedEvent::Create(path) => {
            sender.send((path, ChangeKind::Create)).unwrap();
        }
        DebouncedEvent::Write(path) => {
            sender.send((path, ChangeKind::Write)).unwrap();
        }
        DebouncedEvent::Remove(path) => {
            sender.send((path, ChangeKind::Remove)).unwrap();
        }
        DebouncedEvent::Rename(src, dst) => {
            sender.send((src, ChangeKind::Remove)).unwrap();
            sender.send((dst, ChangeKind::Create)).unwrap();
        }
        DebouncedEvent::Error(err, path) => {
            // TODO: should we reload the file contents?
            log::warn!("watcher error \"{}\", {:?}", err, path);
        }
    }
}

fn handle_change(
    watcher: Option<&mut RecommendedWatcher>,
    sender: &Sender<VfsTask>,
    roots: &Roots,
    path: PathBuf,
    kind: ChangeKind,
) {
    let (root, rel_path) = match roots.find(&path) {
        None => return,
        Some(it) => it,
    };
    match kind {
        ChangeKind::Create => {
            let mut paths = Vec::new();
            if path.is_dir() {
                paths.extend(watch_recursive(watcher, &path, roots, root));
            } else {
                paths.push(rel_path);
            }
            paths
                .into_iter()
                .try_for_each(|rel_path| {
                    let abs_path = rel_path.to_path(&roots.path(root));
                    let text = read_to_string(&abs_path);
                    let res = TaskResult::SingleFile { root, path: rel_path, text };
                    sender.send(VfsTask(res))
                })
                .unwrap()
        }
        ChangeKind::Write | ChangeKind::Remove => {
            let text = read_to_string(&path);
            let res = TaskResult::SingleFile { root, path: rel_path, text };
            sender.send(VfsTask(res)).unwrap();
        }
    }
}

fn watch_recursive(
    mut watcher: Option<&mut RecommendedWatcher>,
    dir: &Path,
    roots: &Roots,
    root: VfsRoot,
) -> Vec<RelativePathBuf> {
    let mut files = Vec::new();
    for entry in WalkDir::new(dir)
        .into_iter()
        .filter_entry(|it| roots.contains(root, it.path()).is_some())
        .filter_map(|it| it.map_err(|e| log::warn!("watcher error: {}", e)).ok())
    {
        if entry.file_type().is_dir() {
            if let Some(watcher) = &mut watcher {
                watch_one(watcher, entry.path());
            }
        } else {
            let path = roots.contains(root, entry.path()).unwrap();
            files.push(path.to_owned());
        }
    }
    files
}

fn watch_one(watcher: &mut RecommendedWatcher, dir: &Path) {
    match watcher.watch(dir, RecursiveMode::NonRecursive) {
        Ok(()) => log::debug!("watching \"{}\"", dir.display()),
        Err(e) => log::warn!("could not watch \"{}\": {}", dir.display(), e),
    }
}

fn read_to_string(path: &Path) -> Option<String> {
    fs::read_to_string(&path).map_err(|e| log::warn!("failed to read file {}", e)).ok()
}
<commit_msg>better comments<commit_after>use std::{
    fs,
    path::{Path, PathBuf},
    sync::{mpsc, Arc},
    time::Duration,
    thread,
};
use crossbeam_channel::{Sender, Receiver, unbounded, RecvError, select};
use relative_path::RelativePathBuf;
use walkdir::WalkDir;
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as _Watcher};

use crate::{Roots, VfsRoot, VfsTask};

pub(crate) enum Task {
    AddRoot { root: VfsRoot },
}

/// `TaskResult` transfers files read on the IO thread to the VFS on the main
/// thread.
#[derive(Debug)]
pub(crate) enum TaskResult {
    /// Emitted when we've recursively scanned a source root during the initial
    /// load.
    BulkLoadRoot { root: VfsRoot, files: Vec<(RelativePathBuf, String)> },
    /// Emitted when we've noticed that a single file has changed.
    ///
    /// Note that this by design does not distinguish between
    /// create/delete/write events, and instead specifies the *current* state of
    /// the file. The idea is to guarantee that in the quiescent state the sum
    /// of all results equals to the current state of the file system, while
    /// allowing to skip intermediate events in non-quiescent states.
    SingleFile { root: VfsRoot, path: RelativePathBuf, text: Option<String> },
}

/// The kind of raw notification we've received from the notify library.
///
/// Note that these are not necessary 100% precise (for example we might receive
/// `Create` instead of `Write`, see #734), but we try do distinguish `Create`s
/// to implement recursive watching of directories.
#[derive(Debug)]
enum ChangeKind {
    Create,
    Write,
    Remove,
}

const WATCHER_DELAY: Duration = Duration::from_millis(250);

// Like thread::JoinHandle, but joins the thread on drop.
//
// This is useful because it guarantees the absence of run-away threads, even if
// code panics. This is important, because we might see panics in the test and
// we might be used in an IDE context, where a failed component is just
// restarted.
//
// Because all threads are joined, care must be taken to avoid deadlocks. That
// typically means ensuring that channels are dropped before the threads.
struct ScopedThread(Option<thread::JoinHandle<()>>);

impl ScopedThread {
    fn spawn(name: String, f: impl FnOnce() + Send + 'static) -> ScopedThread {
        let handle = thread::Builder::new().name(name).spawn(f).unwrap();
        ScopedThread(Some(handle))
    }
}

impl Drop for ScopedThread {
    fn drop(&mut self) {
        let res = self.0.take().unwrap().join();
        if !thread::panicking() {
            res.unwrap();
        }
    }
}

pub(crate) struct Worker {
    // XXX: field order is significant here.
    //
    // In Rust, fields are dropped in the declaration order, and we rely on this
    // here. We must close sender first, so that the  `thread` (who holds the
    // opposite side of the channel) noticed shutdown. Then, we must join the
    // thread, but we must keep receiver alive so that the thread does not
    // panic.
    pub(crate) sender: Sender<Task>,
    _thread: ScopedThread,
    pub(crate) receiver: Receiver<VfsTask>,
}

pub(crate) fn start(roots: Arc<Roots>) -> Worker {
    // This is a pretty elaborate setup of threads & channels! It is
    // explained by the following concerns:
    //    * we need to burn a thread translating from notify's mpsc to
    //      crossbeam_channel.
    //    * we want to read all files from a single thread, to guarantee that
    //      we always get fresher versions and never go back in time.
    //    * we want to tear down everything neatly during shutdown.
    let _thread;
    // This are the channels we use to communicate with outside world.
    // If `input_receiver` is closed we need to tear ourselves down.
    // `output_sender` should not be closed unless the parent died.
    let (input_sender, input_receiver) = unbounded();
    let (output_sender, output_receiver) = unbounded();

    _thread = ScopedThread::spawn("vfs".to_string(), move || {
        // Make sure that the destruction order is
        //
        // * notify_sender
        // * _thread
        // * watcher_sender
        //
        // this is required to avoid deadlocks.

        // These are the corresponding crossbeam channels
        let (watcher_sender, watcher_receiver) = unbounded();
        let _notify_thread;
        {
            // These are `std` channels notify will send events to
            let (notify_sender, notify_receiver) = mpsc::channel();

            let mut watcher = notify::watcher(notify_sender, WATCHER_DELAY)
                .map_err(|e| log::error!("failed to spawn notify {}", e))
                .ok();
            // Start a silly thread to transform between two channels
            _notify_thread = ScopedThread::spawn("notify-convertor".to_string(), move || {
                notify_receiver
                    .into_iter()
                    .for_each(|event| convert_notify_event(event, &watcher_sender))
            });

            // Process requests from the called or notifications from
            // watcher until the caller says stop.
            loop {
                select! {
                    // Received request from the caller. If this channel is
                    // closed, we should shutdown everything.
                    recv(input_receiver) -> t => match t {
                        Err(RecvError) => {
                            drop(input_receiver);
                            break
                        },
                        Ok(Task::AddRoot { root }) => {
                            watch_root(watcher.as_mut(), &output_sender, &*roots, root);
                        }
                    },
                    // Watcher send us changes. If **this** channel is
                    // closed, the watcher has died, which indicates a bug
                    // -- escalate!
                    recv(watcher_receiver) -> event => match event {
                        Err(RecvError) => panic!("watcher is dead"),
                        Ok((path, change)) => {
                            handle_change(watcher.as_mut(), &output_sender, &*roots, path, change);
                        }
                    },
                }
            }
        }
        // Drain pending events: we are not interested in them anyways!
        watcher_receiver.into_iter().for_each(|_| ());
    });
    Worker { sender: input_sender, _thread, receiver: output_receiver }
}

fn watch_root(
    watcher: Option<&mut RecommendedWatcher>,
    sender: &Sender<VfsTask>,
    roots: &Roots,
    root: VfsRoot,
) {
    let root_path = roots.path(root);
    log::debug!("loading {} ...", root_path.display());
    let files = watch_recursive(watcher, root_path, roots, root)
        .into_iter()
        .filter_map(|path| {
            let abs_path = path.to_path(&root_path);
            let text = read_to_string(&abs_path)?;
            Some((path, text))
        })
        .collect();
    let res = TaskResult::BulkLoadRoot { root, files };
    sender.send(VfsTask(res)).unwrap();
    log::debug!("... loaded {}", root_path.display());
}

fn convert_notify_event(event: DebouncedEvent, sender: &Sender<(PathBuf, ChangeKind)>) {
    // forward relevant events only
    match event {
        DebouncedEvent::NoticeWrite(_)
        | DebouncedEvent::NoticeRemove(_)
        | DebouncedEvent::Chmod(_) => {
            // ignore
        }
        DebouncedEvent::Rescan => {
            // TODO: rescan all roots
        }
        DebouncedEvent::Create(path) => {
            sender.send((path, ChangeKind::Create)).unwrap();
        }
        DebouncedEvent::Write(path) => {
            sender.send((path, ChangeKind::Write)).unwrap();
        }
        DebouncedEvent::Remove(path) => {
            sender.send((path, ChangeKind::Remove)).unwrap();
        }
        DebouncedEvent::Rename(src, dst) => {
            sender.send((src, ChangeKind::Remove)).unwrap();
            sender.send((dst, ChangeKind::Create)).unwrap();
        }
        DebouncedEvent::Error(err, path) => {
            // TODO: should we reload the file contents?
            log::warn!("watcher error \"{}\", {:?}", err, path);
        }
    }
}

fn handle_change(
    watcher: Option<&mut RecommendedWatcher>,
    sender: &Sender<VfsTask>,
    roots: &Roots,
    path: PathBuf,
    kind: ChangeKind,
) {
    let (root, rel_path) = match roots.find(&path) {
        None => return,
        Some(it) => it,
    };
    match kind {
        ChangeKind::Create => {
            let mut paths = Vec::new();
            if path.is_dir() {
                paths.extend(watch_recursive(watcher, &path, roots, root));
            } else {
                paths.push(rel_path);
            }
            paths
                .into_iter()
                .try_for_each(|rel_path| {
                    let abs_path = rel_path.to_path(&roots.path(root));
                    let text = read_to_string(&abs_path);
                    let res = TaskResult::SingleFile { root, path: rel_path, text };
                    sender.send(VfsTask(res))
                })
                .unwrap()
        }
        ChangeKind::Write | ChangeKind::Remove => {
            let text = read_to_string(&path);
            let res = TaskResult::SingleFile { root, path: rel_path, text };
            sender.send(VfsTask(res)).unwrap();
        }
    }
}

fn watch_recursive(
    mut watcher: Option<&mut RecommendedWatcher>,
    dir: &Path,
    roots: &Roots,
    root: VfsRoot,
) -> Vec<RelativePathBuf> {
    let mut files = Vec::new();
    for entry in WalkDir::new(dir)
        .into_iter()
        .filter_entry(|it| roots.contains(root, it.path()).is_some())
        .filter_map(|it| it.map_err(|e| log::warn!("watcher error: {}", e)).ok())
    {
        if entry.file_type().is_dir() {
            if let Some(watcher) = &mut watcher {
                watch_one(watcher, entry.path());
            }
        } else {
            let path = roots.contains(root, entry.path()).unwrap();
            files.push(path.to_owned());
        }
    }
    files
}

fn watch_one(watcher: &mut RecommendedWatcher, dir: &Path) {
    match watcher.watch(dir, RecursiveMode::NonRecursive) {
        Ok(()) => log::debug!("watching \"{}\"", dir.display()),
        Err(e) => log::warn!("could not watch \"{}\": {}", dir.display(), e),
    }
}

fn read_to_string(path: &Path) -> Option<String> {
    fs::read_to_string(&path).map_err(|e| log::warn!("failed to read file {}", e)).ok()
}
<|endoftext|>


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

#![feature(append)]
#![feature(arc_unique)]
#![feature(box_syntax)]
#![feature(filling_drop)]
#![feature(hashmap_hasher)]
#![feature(heap_api)]
#![feature(mpsc_select)]
#![feature(plugin)]
#![feature(raw)]
#![feature(slice_chars)]
#![feature(str_char)]
#![feature(unsafe_no_drop_flag)]

#![deny(unsafe_code)]
#![allow(unrooted_must_root)]

#![plugin(string_cache_plugin)]
#![plugin(plugins)]

#[macro_use]
extern crate log;

#[macro_use]
extern crate bitflags;

#[macro_use]
#[no_link]
extern crate plugins as servo_plugins;
extern crate net_traits;
#[macro_use]
extern crate profile_traits;

#[macro_use]
extern crate util;

extern crate rustc_serialize;
extern crate azure;
extern crate canvas_traits;
extern crate clock_ticks;
extern crate cssparser;
extern crate encoding;
extern crate fnv;
extern crate euclid;
extern crate gfx;
extern crate gfx_traits;
extern crate layout_traits;
extern crate libc;
extern crate msg;
extern crate script;
extern crate script_traits;
extern crate selectors;
extern crate smallvec;
extern crate string_cache;
extern crate style;
extern crate url;

// Listed first because of macro definitions
pub mod layout_debug;

pub mod animation;
pub mod block;
pub mod construct;
pub mod context;
pub mod data;
pub mod display_list_builder;
pub mod floats;
pub mod flow;
pub mod flow_list;
pub mod flow_ref;
pub mod fragment;
pub mod generated_content;
pub mod layout_task;
pub mod incremental;
pub mod inline;
pub mod list_item;
pub mod model;
pub mod multicol;
pub mod opaque_node;
pub mod parallel;
pub mod sequential;
pub mod table_wrapper;
pub mod table;
pub mod table_caption;
pub mod table_colgroup;
pub mod table_rowgroup;
pub mod table_row;
pub mod table_cell;
pub mod text;
pub mod traversal;
pub mod wrapper;

pub mod css {
    pub mod matching;
    pub mod node_style;
}
<commit_msg>Auto merge of #6577 - Ms2ger:disallow-unrooted-layout, r=jdm<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/. */

#![feature(append)]
#![feature(arc_unique)]
#![feature(box_syntax)]
#![feature(filling_drop)]
#![feature(hashmap_hasher)]
#![feature(heap_api)]
#![feature(mpsc_select)]
#![feature(plugin)]
#![feature(raw)]
#![feature(slice_chars)]
#![feature(str_char)]
#![feature(unsafe_no_drop_flag)]

#![deny(unsafe_code)]

#![plugin(string_cache_plugin)]
#![plugin(plugins)]

#[macro_use]
extern crate log;

#[macro_use]
extern crate bitflags;

#[macro_use]
#[no_link]
extern crate plugins as servo_plugins;
extern crate net_traits;
#[macro_use]
extern crate profile_traits;

#[macro_use]
extern crate util;

extern crate rustc_serialize;
extern crate azure;
extern crate canvas_traits;
extern crate clock_ticks;
extern crate cssparser;
extern crate encoding;
extern crate fnv;
extern crate euclid;
extern crate gfx;
extern crate gfx_traits;
extern crate layout_traits;
extern crate libc;
extern crate msg;
extern crate script;
extern crate script_traits;
extern crate selectors;
extern crate smallvec;
extern crate string_cache;
extern crate style;
extern crate url;

// Listed first because of macro definitions
pub mod layout_debug;

pub mod animation;
pub mod block;
pub mod construct;
pub mod context;
pub mod data;
pub mod display_list_builder;
pub mod floats;
pub mod flow;
pub mod flow_list;
pub mod flow_ref;
pub mod fragment;
pub mod generated_content;
pub mod layout_task;
pub mod incremental;
pub mod inline;
pub mod list_item;
pub mod model;
pub mod multicol;
pub mod opaque_node;
pub mod parallel;
pub mod sequential;
pub mod table_wrapper;
pub mod table;
pub mod table_caption;
pub mod table_colgroup;
pub mod table_rowgroup;
pub mod table_row;
pub mod table_cell;
pub mod text;
pub mod traversal;
pub mod wrapper;

pub mod css {
    pub mod matching;
    pub mod node_style;
}
<|endoftext|>