<commit_before>use alloc::boxed::*;

use string::*;
use vec::Vec;

use event::*;

use orbital::*;
use graphics::color::Color;

use rand_old::*;

static mut window: *mut ConsoleWindow = 0 as *mut ConsoleWindow;

/// Create a new console window
pub fn console_window() -> &'static mut ConsoleWindow {
    unsafe {
        if window as usize == 0 {
            window = Box::into_raw(ConsoleWindow::new((rand() % 400 + 50) as isize,
                                          (rand() % 300 + 50) as isize,
                                          640,
                                          480,
                                          "Console"));
            (*window).sync();
        }
        &mut *window
    }
}

/// Initialize console
pub unsafe fn console_init() {
    window = 0 as *mut ConsoleWindow;
}

/// Destroy the console
pub unsafe fn console_destroy() {
    if window as usize > 0 {
        drop(Box::from_raw(window));
        window = 0 as *mut ConsoleWindow;
    }
}

/// Set the title of the console window
// TODO: Move this to a `Window` trait?
pub fn console_title(title: &str) {
    console_window().set_title(title);
}

/// Print to console
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
        console_window().print(&format!($($arg)*), $crate::Color::rgba(224, 224, 224, 255));
        console_window().sync();
    });
}

/// Print to console with color
#[macro_export]
macro_rules! print_color {
    ($color:expr, $($arg:tt)*) => ({
        console_window().print(&format!($($arg)*), $color);
        console_window().sync();
    });
}

/// Print new line to console
#[macro_export]
macro_rules! println {
    ($($arg:tt)*) => ({
        print!($($arg)*);
        print!("\n");
    });
}

/// Print new line to console with color
#[macro_export]
macro_rules! println_color {
    ($color:expr, $($arg:tt)*) => ({
        print_color!($color, $($arg)*);
        print_color!($color, "\n");
    });
}

/// Read a line from the console
#[macro_export]
macro_rules! readln {
    () => (console_window().read());
}

/// A console char
pub struct ConsoleChar {
    /// The char
    character: char,
    /// The color
    color: Color,
}

/// A console window
pub struct ConsoleWindow {
    /// The window
    pub window: Box<Window>,
    /// The char buffer
    pub output: Vec<ConsoleChar>,
    /// The current input command
    pub command: String,
    /// Offset
    pub offset: usize,
    /// Scroll distance x
    pub scroll_x: isize,
    /// Scroll distance y
    pub scroll_y: isize,
    /// Wrap the text, if true
    pub wrap: bool,
}

impl ConsoleWindow {
    /// Create a new console window
    pub fn new(x: isize, y: isize, w: usize, h: usize, title: &str) -> Box<Self> {
        box ConsoleWindow {
            window: Window::new(x, y, w, h, title).unwrap(),
            output: Vec::new(),
            command: String::new(),
            offset: 0,
            scroll_x: 0,
            scroll_y: 0,
            wrap: true,
        }
    }

    /// Set the window title
    pub fn set_title(&mut self, title: &str) {
        //TODO THIS IS A HACK, should use self.window.setTitle(title);
        self.window = Window::new(self.window.x(),
                                  self.window.y(),
                                  self.window.width(),
                                  self.window.height(),
                                  title).unwrap();
    }

    /// Poll the window
    pub fn poll(&mut self) -> Option<Event> {
        self.window.poll()
    }

    /// Print to the window
    pub fn print(&mut self, string: &str, color: Color) {
        for c in string.chars() {
            self.output.push(ConsoleChar {
                character: c,
                color: color,
            });
        }
    }

    /// Read input
    pub fn read(&mut self) -> Option<String> {
        while let Some(event) = self.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            K_BKSP => if self.offset > 0 {
                                self.command = self.command[0 .. self.offset - 1].to_string() +
                                               &self.command[self.offset .. self.command.len()];
                                self.offset -= 1;
                            },
                            K_DEL => if self.offset < self.command.len() {
                                self.command =
                                    self.command[0 .. self.offset].to_string() +
                                    &self.command[self.offset + 1 .. self.command.len() - 1];
                            },
                            K_HOME => self.offset = 0,
                            K_UP => {
                                //self.command = self.last_command.clone();
                                //self.offset = self.command.len();
                            }
                            K_LEFT => if self.offset > 0 {
                                self.offset -= 1;
                            },
                            K_RIGHT => if self.offset < self.command.len() {
                                self.offset += 1;
                            },
                            K_END => self.offset = self.command.len(),
                            K_DOWN => {
                                //self.command.clear()
                                //self.offset = self.command.len();
                            }
                            _ => match key_event.character {
                                '\x00' => (),
                                '\n' => {
                                    let command = self.command.clone();
                                    self.command.clear();
                                    self.offset = 0;
                                    return Some(command);
                                }
                                '\x1B' => break,
                                _ => {
                                    self.command = self.command[0 .. self.offset].to_string() +
                                                   &key_event.character.to_string() +
                                                   &self.command[self.offset .. self.command.len()];
                                    self.offset += 1;
                                }
                            },
                        }
                    }
                    self.sync();
                }
                _ => (),
            }
        }

        return None;
    }

    /// Redraw the window
    pub fn sync(&mut self) {
        let scroll_x = self.scroll_x;
        let scroll_y = self.scroll_y;

        let mut col = -scroll_x;
        let cols = self.window.width() as isize / 8;
        let mut row = -scroll_y;
        let rows = self.window.height() as isize / 16;

        {
            self.window.set(Color::BLACK);

            for c in self.output.iter() {
                if self.wrap && col >= cols {
                    col = -scroll_x;
                    row += 1;
                }

                if c.character == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c.character == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        self.window.char(8 * col, 16 * row, c.character, c.color);
                    }
                    col += 1;
                }
            }

            if col > -scroll_x {
                col = -scroll_x;
                row += 1;
            }

            if col >= 0 && col < cols && row >= 0 && row < rows {
                self.window.char(8 * col, 16 * row, '#', Color::WHITE);
                col += 2;
            }

            let mut i = 0;
            for c in self.command.chars() {
                if self.wrap && col >= cols {
                    col = -scroll_x;
                    row += 1;
                }

                if self.offset == i && col >= 0 && col < cols && row >= 0 && row < rows {
                    self.window.char(8 * col, 16 * row, '_', Color::WHITE);
                }

                if c == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        self.window.char(8 * col, 16 * row, c, Color::WHITE);
                    }
                    col += 1;
                }

                i += 1;
            }

            if self.wrap && col >= cols {
                col = -scroll_x;
                row += 1;
            }

            if self.offset == i && col >= 0 && col < cols && row >= 0 && row < rows {
                self.window.char(8 * col, 16 * row, '_', Color::WHITE);
            }
        }

        self.window.sync();

        if row >= rows {
            self.scroll_y += row - rows + 1;

            self.sync();
        }
    }
}
<commit_msg>more if letting<commit_after>use alloc::boxed::*;

use string::*;
use vec::Vec;

use event::*;

use orbital::*;
use graphics::color::Color;

use rand_old::*;

static mut window: *mut ConsoleWindow = 0 as *mut ConsoleWindow;

/// Create a new console window
pub fn console_window() -> &'static mut ConsoleWindow {
    unsafe {
        if window as usize == 0 {
            window = Box::into_raw(ConsoleWindow::new((rand() % 400 + 50) as isize,
                                   (rand() % 300 + 50) as isize,
                                   640,
                                   480,
                                   "Console"));
            (*window).sync();
        }
        &mut *window
    }
}

/// Initialize console
pub unsafe fn console_init() {
    window = 0 as *mut ConsoleWindow;
}

/// Destroy the console
pub unsafe fn console_destroy() {
    if window as usize > 0 {
        drop(Box::from_raw(window));
        window = 0 as *mut ConsoleWindow;
    }
}

/// Set the title of the console window
// TODO: Move this to a `Window` trait?
pub fn console_title(title: &str) {
    console_window().set_title(title);
}

/// Print to console
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
        console_window().print(&format!($($arg)*), $crate::Color::rgba(224, 224, 224, 255));
        console_window().sync();
    });
}

/// Print to console with color
#[macro_export]
macro_rules! print_color {
    ($color:expr, $($arg:tt)*) => ({
        console_window().print(&format!($($arg)*), $color);
        console_window().sync();
    });
}

/// Print new line to console
#[macro_export]
macro_rules! println {
    ($($arg:tt)*) => ({
        print!($($arg)*);
        print!("\n");
    });
}

/// Print new line to console with color
#[macro_export]
macro_rules! println_color {
    ($color:expr, $($arg:tt)*) => ({
        print_color!($color, $($arg)*);
        print_color!($color, "\n");
    });
}

/// Read a line from the console
#[macro_export]
macro_rules! readln {
    () => (console_window().read());
}

/// A console char
pub struct ConsoleChar {
    /// The char
    character: char,
    /// The color
    color: Color,
}

/// A console window
pub struct ConsoleWindow {
    /// The window
    pub window: Box<Window>,
    /// The char buffer
    pub output: Vec<ConsoleChar>,
    /// The current input command
    pub command: String,
    /// Offset
    pub offset: usize,
    /// Scroll distance x
    pub scroll_x: isize,
    /// Scroll distance y
    pub scroll_y: isize,
    /// Wrap the text, if true
    pub wrap: bool,
}

impl ConsoleWindow {
    /// Create a new console window
    pub fn new(x: isize, y: isize, w: usize, h: usize, title: &str) -> Box<Self> {
        box ConsoleWindow {
            window: Window::new(x, y, w, h, title).unwrap(),
            output: Vec::new(),
            command: String::new(),
            offset: 0,
            scroll_x: 0,
            scroll_y: 0,
            wrap: true,
        }
    }

    /// Set the window title
    pub fn set_title(&mut self, title: &str) {
        //TODO THIS IS A HACK, should use self.window.setTitle(title);
        self.window = Window::new(self.window.x(),
                                  self.window.y(),
                                  self.window.width(),
                                  self.window.height(),
                                  title).unwrap();
    }

    /// Poll the window
    pub fn poll(&mut self) -> Option<Event> {
        self.window.poll()
    }

    /// Print to the window
    pub fn print(&mut self, string: &str, color: Color) {
        for c in string.chars() {
            self.output.push(ConsoleChar {
                character: c,
                color: color,
            });
        }
    }

    /// Read input
    pub fn read(&mut self) -> Option<String> {
        while let Some(event) = self.poll() {
            if let EventOption::Key(key_event) = event.to_option() {
                if key_event.pressed {
                    match key_event.scancode {
                        K_BKSP => if self.offset > 0 {
                            self.command = self.command[0 .. self.offset - 1].to_string() +
                                           &self.command[self.offset .. self.command.len()];
                            self.offset -= 1;
                        },
                        K_DEL => if self.offset < self.command.len() {
                            self.command =
                                self.command[0 .. self.offset].to_string() +
                                &self.command[self.offset + 1 .. self.command.len() - 1];
                        },
                        K_HOME => self.offset = 0,
                        K_UP => {
                            //self.command = self.last_command.clone();
                            //self.offset = self.command.len();
                        }
                        K_LEFT => if self.offset > 0 {
                            self.offset -= 1;
                        },
                        K_RIGHT => if self.offset < self.command.len() {
                            self.offset += 1;
                        },
                        K_END => self.offset = self.command.len(),
                        K_DOWN => {
                            //self.command.clear()
                            //self.offset = self.command.len();
                        }
                        _ => match key_event.character {
                            '\x00' => (),
                            '\n' => {
                                let command = self.command.clone();
                                self.command.clear();
                                self.offset = 0;
                                return Some(command);
                            }
                            '\x1B' => break,
                            _ => {
                                self.command = self.command[0 .. self.offset].to_string() +
                                               &key_event.character.to_string() +
                                               &self.command[self.offset .. self.command.len()];
                                self.offset += 1;
                            }
                        },
                    }
                }
                self.sync();
            }
        }

        return None;
    }

    /// Redraw the window
    pub fn sync(&mut self) {
        let scroll_x = self.scroll_x;
        let scroll_y = self.scroll_y;

        let mut col = -scroll_x;
        let cols = self.window.width() as isize / 8;
        let mut row = -scroll_y;
        let rows = self.window.height() as isize / 16;

        {
            self.window.set(Color::BLACK);

            for c in self.output.iter() {
                if self.wrap && col >= cols {
                    col = -scroll_x;
                    row += 1;
                }

                if c.character == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c.character == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        self.window.char(8 * col, 16 * row, c.character, c.color);
                    }
                    col += 1;
                }
            }

            if col > -scroll_x {
                col = -scroll_x;
                row += 1;
            }

            if col >= 0 && col < cols && row >= 0 && row < rows {
                self.window.char(8 * col, 16 * row, '#', Color::WHITE);
                col += 2;
            }

            let mut i = 0;
            for c in self.command.chars() {
                if self.wrap && col >= cols {
                    col = -scroll_x;
                    row += 1;
                }

                if self.offset == i && col >= 0 && col < cols && row >= 0 && row < rows {
                    self.window.char(8 * col, 16 * row, '_', Color::WHITE);
                }

                if c == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        self.window.char(8 * col, 16 * row, c, Color::WHITE);
                    }
                    col += 1;
                }

                i += 1;
            }

            if self.wrap && col >= cols {
                col = -scroll_x;
                row += 1;
            }

            if self.offset == i && col >= 0 && col < cols && row >= 0 && row < rows {
                self.window.char(8 * col, 16 * row, '_', Color::WHITE);
            }
        }

        self.window.sync();

        if row >= rows {
            self.scroll_y += row - rows + 1;

            self.sync();
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    build::main();
}

#[cfg(feature = "bundled")]
mod build {
    extern crate cc;
    use std::{env, fs};
    use std::path::Path;

    pub fn main() {
        if cfg!(feature = "sqlcipher") {
            panic!("Builds with bundled SQLCipher are not supported");
        }

        let out_dir = env::var("OUT_DIR").unwrap();
        let out_path = Path::new(&out_dir).join("bindgen.rs");
        fs::copy("sqlite3/bindgen_bundled_version.rs", out_path)
            .expect("Could not copy bindings to output directory");

        cc::Build::new()
            .file("sqlite3/sqlite3.c")
            .flag("-DSQLITE_CORE")
            .flag("-DSQLITE_DEFAULT_FOREIGN_KEYS=1")
            .flag("-DSQLITE_ENABLE_API_ARMOR")
            .flag("-DSQLITE_ENABLE_COLUMN_METADATA")
            .flag("-DSQLITE_ENABLE_DBSTAT_VTAB")
            .flag("-DSQLITE_ENABLE_FTS3")
            .flag("-DSQLITE_ENABLE_FTS3_PARENTHESIS")
            .flag("-DSQLITE_ENABLE_FTS5")
            .flag("-DSQLITE_ENABLE_JSON1")
            .flag("-DSQLITE_ENABLE_LOAD_EXTENSION=1")
            .flag("-DSQLITE_ENABLE_MEMORY_MANAGEMENT")
            .flag("-DSQLITE_ENABLE_RTREE")
            .flag("-DSQLITE_ENABLE_STAT2")
            .flag("-DSQLITE_ENABLE_STAT4")
            .flag("-DSQLITE_HAVE_ISNAN")
            .flag("-DSQLITE_SOUNDEX")
            .flag("-DSQLITE_THREADSAFE=1")
            .flag("-DSQLITE_USE_URI")
            .flag("-DHAVE_USLEEP=1")
            .compile("libsqlite3.a");
    }
}

#[cfg(not(feature = "bundled"))]
mod build {
    extern crate pkg_config;

    #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
    extern crate vcpkg;

    use std::env;

    pub enum HeaderLocation {
        FromEnvironment,
        Wrapper,
        FromPath(String),
    }

    impl From<HeaderLocation> for String {
        fn from(header: HeaderLocation) -> String {
            match header {
                HeaderLocation::FromEnvironment => {
                    let prefix = env_prefix();
                    let mut header = env::var(format!("{}_INCLUDE_DIR", prefix))
                        .expect(&format!("{}_INCLUDE_DIR must be set if {}_LIB_DIR is set", prefix, prefix));
                    header.push_str("/sqlite3.h");
                    header
                }
                HeaderLocation::Wrapper => "wrapper.h".into(),
                HeaderLocation::FromPath(path) => path,
            }
        }
    }

    pub fn main() {
        let header = find_sqlite();
        bindings::write_to_out_dir(header);
    }

    // Prints the necessary cargo link commands and returns the path to the header.
    fn find_sqlite() -> HeaderLocation {
        let link_lib = link_lib();

        // Allow users to specify where to find SQLite.
        if let Ok(dir) = env::var(format!("{}_LIB_DIR", env_prefix())) {
            println!("cargo:rustc-link-lib={}", link_lib);
            println!("cargo:rustc-link-search={}", dir);
            return HeaderLocation::FromEnvironment;
        }

        if let Some(header) = try_vcpkg() {
            return header;
        }

        // See if pkg-config can do everything for us.
        match pkg_config::Config::new().print_system_libs(false).probe(link_lib) {
            Ok(mut lib) => {
                if let Some(mut header) = lib.include_paths.pop() {
                    header.push("sqlite3.h");
                    HeaderLocation::FromPath(header.to_string_lossy().into())
                } else {
                    HeaderLocation::Wrapper
                }
            }
            Err(_) => {
                // No env var set and pkg-config couldn't help; just output the link-lib
                // request and hope that the library exists on the system paths. We used to
                // output /usr/lib explicitly, but that can introduce other linking problems; see
                // https://github.com/jgallagher/rusqlite/issues/207.
                println!("cargo:rustc-link-lib={}", link_lib);
                HeaderLocation::Wrapper
            }
        }
    }

    #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
    fn try_vcpkg() -> Option<HeaderLocation> {
        // See if vcpkg can find it.
        if let Ok(mut lib) = vcpkg::Config::new().probe(link_lib()) {
            if let Some(mut header) = lib.include_paths.pop() {
                header.push("sqlite3.h");
                return Some(HeaderLocation::FromPath(header.to_string_lossy().into()));
            }
        }
        None
    }

    #[cfg(not(all(feature = "vcpkg", target_env = "msvc")))]
    fn try_vcpkg() -> Option<HeaderLocation> {
        None
    }

    fn env_prefix() -> &'static str {
        if cfg!(feature = "sqlcipher") {
            "SQLCIPHER"
        } else {
            "SQLITE3"
        }
    }

    fn link_lib() -> &'static str {
        if cfg!(feature = "sqlcipher") {
            "sqlcipher"
        } else {
            "sqlite3"
        }
    }

    #[cfg(not(feature = "buildtime_bindgen"))]
    mod bindings {
        use super::HeaderLocation;

        use std::{env, fs};
        use std::path::Path;

        #[cfg_attr(rustfmt, rustfmt_skip)]
        static PREBUILT_BINDGEN_PATHS: &'static [&'static str] = &[
            "bindgen-bindings/bindgen_3.6.8.rs",

            #[cfg(feature = "min_sqlite_version_3_6_11")]
            "bindgen-bindings/bindgen_3.6.11.rs",

            #[cfg(feature = "min_sqlite_version_3_6_23")]
            "bindgen-bindings/bindgen_3.6.23.rs",

            #[cfg(feature = "min_sqlite_version_3_7_3")]
            "bindgen-bindings/bindgen_3.7.3.rs",

            #[cfg(feature = "min_sqlite_version_3_7_4")]
            "bindgen-bindings/bindgen_3.7.4.rs",

            #[cfg(feature = "min_sqlite_version_3_7_16")]
            "bindgen-bindings/bindgen_3.7.16.rs",
        ];

        pub fn write_to_out_dir(_header: HeaderLocation) {
            let out_dir = env::var("OUT_DIR").unwrap();
            let out_path = Path::new(&out_dir).join("bindgen.rs");
            let in_path = PREBUILT_BINDGEN_PATHS[PREBUILT_BINDGEN_PATHS.len() - 1];
            fs::copy(in_path, out_path).expect("Could not copy bindings to output directory");
        }
    }

    #[cfg(feature = "buildtime_bindgen")]
    mod bindings {
        extern crate bindgen;

        use self::bindgen::callbacks::{ParseCallbacks, IntKind};
        use super::HeaderLocation;

        use std::env;
        use std::io::Write;
        use std::fs::OpenOptions;
        use std::path::Path;

        #[derive(Debug)]
        struct SqliteTypeChooser;

        impl ParseCallbacks for SqliteTypeChooser {
            fn int_macro(&self, _name: &str, value: i64) -> Option<IntKind> {
                if value >= i32::min_value() as i64 && value <= i32::max_value() as i64 {
                    Some(IntKind::I32)
                } else {
                    None
                }
            }
        }

        pub fn write_to_out_dir(header: HeaderLocation) {
            let header: String = header.into();
            let out_dir = env::var("OUT_DIR").unwrap();
            let mut output = Vec::new();
            bindgen::builder()
                .header(header.clone())
                .parse_callbacks(Box::new(SqliteTypeChooser))
                .rustfmt_bindings(true)
                .generate()
                .expect(&format!("could not run bindgen on header {}", header))
                .write(Box::new(&mut output))
                .expect("could not write output of bindgen");
            let mut output = String::from_utf8(output).expect("bindgen output was not UTF-8?!");

            // rusqlite's functions feature ors in the SQLITE_DETERMINISTIC flag when it can. This flag
            // was added in SQLite 3.8.3, but oring it in in prior versions of SQLite is harmless. We
            // don't want to not build just because this flag is missing (e.g., if we're linking against
            // SQLite 3.7.x), so append the flag manually if it isn't present in bindgen's output.
            if !output.contains("pub const SQLITE_DETERMINISTIC") {
                output.push_str("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n");
            }

            let path = Path::new(&out_dir).join("bindgen.rs");

            let mut file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(path.clone())
                .expect(&format!("Could not write to {:?}", path));

            file.write_all(output.as_bytes()).expect(&format!("Could not write to {:?}", path));
        }
    }
}
<commit_msg>Use `rerun-if-env-changed` in libsqlite3-sys<commit_after>fn main() {
    build::main();
}

#[cfg(feature = "bundled")]
mod build {
    extern crate cc;
    use std::{env, fs};
    use std::path::Path;

    pub fn main() {
        if cfg!(feature = "sqlcipher") {
            panic!("Builds with bundled SQLCipher are not supported");
        }

        let out_dir = env::var("OUT_DIR").unwrap();
        let out_path = Path::new(&out_dir).join("bindgen.rs");
        fs::copy("sqlite3/bindgen_bundled_version.rs", out_path)
            .expect("Could not copy bindings to output directory");

        cc::Build::new()
            .file("sqlite3/sqlite3.c")
            .flag("-DSQLITE_CORE")
            .flag("-DSQLITE_DEFAULT_FOREIGN_KEYS=1")
            .flag("-DSQLITE_ENABLE_API_ARMOR")
            .flag("-DSQLITE_ENABLE_COLUMN_METADATA")
            .flag("-DSQLITE_ENABLE_DBSTAT_VTAB")
            .flag("-DSQLITE_ENABLE_FTS3")
            .flag("-DSQLITE_ENABLE_FTS3_PARENTHESIS")
            .flag("-DSQLITE_ENABLE_FTS5")
            .flag("-DSQLITE_ENABLE_JSON1")
            .flag("-DSQLITE_ENABLE_LOAD_EXTENSION=1")
            .flag("-DSQLITE_ENABLE_MEMORY_MANAGEMENT")
            .flag("-DSQLITE_ENABLE_RTREE")
            .flag("-DSQLITE_ENABLE_STAT2")
            .flag("-DSQLITE_ENABLE_STAT4")
            .flag("-DSQLITE_HAVE_ISNAN")
            .flag("-DSQLITE_SOUNDEX")
            .flag("-DSQLITE_THREADSAFE=1")
            .flag("-DSQLITE_USE_URI")
            .flag("-DHAVE_USLEEP=1")
            .compile("libsqlite3.a");
    }
}

#[cfg(not(feature = "bundled"))]
mod build {
    extern crate pkg_config;

    #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
    extern crate vcpkg;

    use std::env;

    pub enum HeaderLocation {
        FromEnvironment,
        Wrapper,
        FromPath(String),
    }

    impl From<HeaderLocation> for String {
        fn from(header: HeaderLocation) -> String {
            match header {
                HeaderLocation::FromEnvironment => {
                    let prefix = env_prefix();
                    let mut header = env::var(format!("{}_INCLUDE_DIR", prefix))
                        .expect(&format!("{}_INCLUDE_DIR must be set if {}_LIB_DIR is set", prefix, prefix));
                    header.push_str("/sqlite3.h");
                    header
                }
                HeaderLocation::Wrapper => "wrapper.h".into(),
                HeaderLocation::FromPath(path) => path,
            }
        }
    }

    pub fn main() {
        let header = find_sqlite();
        bindings::write_to_out_dir(header);
    }

    // Prints the necessary cargo link commands and returns the path to the header.
    fn find_sqlite() -> HeaderLocation {
        let link_lib = link_lib();

        println!("cargo:rerun-if-env-changed={}_INCLUDE_DIR", env_prefix());
        println!("cargo:rerun-if-env-changed={}_LIB_DIR", env_prefix());
        if cfg!(target_os="windows") {
            println!("cargo:rerun-if-env-changed=PATH");
        }
        // Allow users to specify where to find SQLite.
        if let Ok(dir) = env::var(format!("{}_LIB_DIR", env_prefix())) {
            println!("cargo:rustc-link-lib={}", link_lib);
            println!("cargo:rustc-link-search={}", dir);
            return HeaderLocation::FromEnvironment;
        }

        if let Some(header) = try_vcpkg() {
            return header;
        }

        // See if pkg-config can do everything for us.
        match pkg_config::Config::new().print_system_libs(false).probe(link_lib) {
            Ok(mut lib) => {
                if let Some(mut header) = lib.include_paths.pop() {
                    header.push("sqlite3.h");
                    HeaderLocation::FromPath(header.to_string_lossy().into())
                } else {
                    HeaderLocation::Wrapper
                }
            }
            Err(_) => {
                // No env var set and pkg-config couldn't help; just output the link-lib
                // request and hope that the library exists on the system paths. We used to
                // output /usr/lib explicitly, but that can introduce other linking problems; see
                // https://github.com/jgallagher/rusqlite/issues/207.
                println!("cargo:rustc-link-lib={}", link_lib);
                HeaderLocation::Wrapper
            }
        }
    }

    #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
    fn try_vcpkg() -> Option<HeaderLocation> {
        // See if vcpkg can find it.
        if let Ok(mut lib) = vcpkg::Config::new().probe(link_lib()) {
            if let Some(mut header) = lib.include_paths.pop() {
                header.push("sqlite3.h");
                return Some(HeaderLocation::FromPath(header.to_string_lossy().into()));
            }
        }
        None
    }

    #[cfg(not(all(feature = "vcpkg", target_env = "msvc")))]
    fn try_vcpkg() -> Option<HeaderLocation> {
        None
    }

    fn env_prefix() -> &'static str {
        if cfg!(feature = "sqlcipher") {
            "SQLCIPHER"
        } else {
            "SQLITE3"
        }
    }

    fn link_lib() -> &'static str {
        if cfg!(feature = "sqlcipher") {
            "sqlcipher"
        } else {
            "sqlite3"
        }
    }

    #[cfg(not(feature = "buildtime_bindgen"))]
    mod bindings {
        use super::HeaderLocation;

        use std::{env, fs};
        use std::path::Path;

        #[cfg_attr(rustfmt, rustfmt_skip)]
        static PREBUILT_BINDGEN_PATHS: &'static [&'static str] = &[
            "bindgen-bindings/bindgen_3.6.8.rs",

            #[cfg(feature = "min_sqlite_version_3_6_11")]
            "bindgen-bindings/bindgen_3.6.11.rs",

            #[cfg(feature = "min_sqlite_version_3_6_23")]
            "bindgen-bindings/bindgen_3.6.23.rs",

            #[cfg(feature = "min_sqlite_version_3_7_3")]
            "bindgen-bindings/bindgen_3.7.3.rs",

            #[cfg(feature = "min_sqlite_version_3_7_4")]
            "bindgen-bindings/bindgen_3.7.4.rs",

            #[cfg(feature = "min_sqlite_version_3_7_16")]
            "bindgen-bindings/bindgen_3.7.16.rs",
        ];

        pub fn write_to_out_dir(_header: HeaderLocation) {
            let out_dir = env::var("OUT_DIR").unwrap();
            let out_path = Path::new(&out_dir).join("bindgen.rs");
            let in_path = PREBUILT_BINDGEN_PATHS[PREBUILT_BINDGEN_PATHS.len() - 1];
            fs::copy(in_path, out_path).expect("Could not copy bindings to output directory");
        }
    }

    #[cfg(feature = "buildtime_bindgen")]
    mod bindings {
        extern crate bindgen;

        use self::bindgen::callbacks::{ParseCallbacks, IntKind};
        use super::HeaderLocation;

        use std::env;
        use std::io::Write;
        use std::fs::OpenOptions;
        use std::path::Path;

        #[derive(Debug)]
        struct SqliteTypeChooser;

        impl ParseCallbacks for SqliteTypeChooser {
            fn int_macro(&self, _name: &str, value: i64) -> Option<IntKind> {
                if value >= i32::min_value() as i64 && value <= i32::max_value() as i64 {
                    Some(IntKind::I32)
                } else {
                    None
                }
            }
        }

        pub fn write_to_out_dir(header: HeaderLocation) {
            let header: String = header.into();
            let out_dir = env::var("OUT_DIR").unwrap();
            let mut output = Vec::new();
            bindgen::builder()
                .header(header.clone())
                .parse_callbacks(Box::new(SqliteTypeChooser))
                .rustfmt_bindings(true)
                .generate()
                .expect(&format!("could not run bindgen on header {}", header))
                .write(Box::new(&mut output))
                .expect("could not write output of bindgen");
            let mut output = String::from_utf8(output).expect("bindgen output was not UTF-8?!");

            // rusqlite's functions feature ors in the SQLITE_DETERMINISTIC flag when it can. This flag
            // was added in SQLite 3.8.3, but oring it in in prior versions of SQLite is harmless. We
            // don't want to not build just because this flag is missing (e.g., if we're linking against
            // SQLite 3.7.x), so append the flag manually if it isn't present in bindgen's output.
            if !output.contains("pub const SQLITE_DETERMINISTIC") {
                output.push_str("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n");
            }

            let path = Path::new(&out_dir).join("bindgen.rs");

            let mut file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(path.clone())
                .expect(&format!("Could not write to {:?}", path));

            file.write_all(output.as_bytes()).expect(&format!("Could not write to {:?}", path));
        }
    }
}
<|endoftext|>


<commit_before>use crate::ty::query::config::QueryAccessors;
use crate::ty::query::plumbing::QueryState;
use crate::ty::query::queries;
use crate::ty::TyCtxt;

use std::any::type_name;
use std::mem;

#[derive(Clone)]
struct QueryStats {
    name: &'static str,
    cache_hits: usize,
    key_size: usize,
    key_type: &'static str,
    value_size: usize,
    value_type: &'static str,
    entry_count: usize,
}

fn stats<'tcx, Q: QueryAccessors<'tcx>>(
    name: &'static str,
    map: &QueryState<'tcx, Q>,
) -> QueryStats {
    QueryStats {
        name,
        #[cfg(debug_assertions)]
        cache_hits: map.cache_hits,
        #[cfg(not(debug_assertions))]
        cache_hits: 0,
        key_size: mem::size_of::<Q::Key>(),
        key_type: type_name::<Q::Key>(),
        value_size: mem::size_of::<Q::Value>(),
        value_type: type_name::<Q::Value>(),
        entry_count: map.iter_results(|results| results.count()),
    }
}

pub fn print_stats(tcx: TyCtxt<'_>) {
    let queries = query_stats(tcx);

    if cfg!(debug_assertions) {
        let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
        let results: usize = queries.iter().map(|s| s.entry_count).sum();
        println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
    }

    let mut query_key_sizes = queries.clone();
    query_key_sizes.sort_by_key(|q| q.key_size);
    println!("\nLarge query keys:");
    for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
        println!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
    }

    let mut query_value_sizes = queries.clone();
    query_value_sizes.sort_by_key(|q| q.value_size);
    println!("\nLarge query values:");
    for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
        println!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
    }

    if cfg!(debug_assertions) {
        let mut query_cache_hits = queries.clone();
        query_cache_hits.sort_by_key(|q| q.cache_hits);
        println!("\nQuery cache hits:");
        for q in query_cache_hits.iter().rev() {
            println!(
                "   {} - {} ({}%)",
                q.name,
                q.cache_hits,
                q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64
            );
        }
    }

    let mut query_value_count = queries.clone();
    query_value_count.sort_by_key(|q| q.entry_count);
    println!("\nQuery value count:");
    for q in query_value_count.iter().rev() {
        println!("   {} - {}", q.name, q.entry_count);
    }
}

macro_rules! print_stats {
    (<$tcx:tt> $($category:tt {
        $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*
    },)*) => {
        fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
            let mut queries = Vec::new();

            $($(
                queries.push(stats::<queries::$name<'_>>(
                    stringify!($name),
                    &tcx.queries.$name,
                ));
            )*)*

            queries
        }
    }
}

rustc_query_append! { [print_stats!][<'tcx>] }
<commit_msg>Add a stat for local DefId density<commit_after>use crate::ty::query::config::QueryAccessors;
use crate::ty::query::plumbing::QueryState;
use crate::ty::query::queries;
use crate::ty::TyCtxt;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};

use std::any::type_name;
use std::mem;

trait KeyStats {
    fn key_stats(&self, stats: &mut QueryStats);
}

impl<T> KeyStats for T {
    default fn key_stats(&self, _: &mut QueryStats) {}
}

impl KeyStats for DefId {
    fn key_stats(&self, stats: &mut QueryStats) {
        if self.krate == LOCAL_CRATE {
            stats.local_def_id_keys = Some(stats.local_def_id_keys.unwrap_or(0) + 1);
        }
    }
}

#[derive(Clone)]
struct QueryStats {
    name: &'static str,
    cache_hits: usize,
    key_size: usize,
    key_type: &'static str,
    value_size: usize,
    value_type: &'static str,
    entry_count: usize,
    local_def_id_keys: Option<usize>,
}

fn stats<'tcx, Q: QueryAccessors<'tcx>>(
    name: &'static str,
    map: &QueryState<'tcx, Q>,
) -> QueryStats {
    let mut stats = QueryStats {
        name,
        #[cfg(debug_assertions)]
        cache_hits: map.cache_hits,
        #[cfg(not(debug_assertions))]
        cache_hits: 0,
        key_size: mem::size_of::<Q::Key>(),
        key_type: type_name::<Q::Key>(),
        value_size: mem::size_of::<Q::Value>(),
        value_type: type_name::<Q::Value>(),
        entry_count: map.iter_results(|results| results.count()),
        local_def_id_keys: None,
    };
    map.iter_results(|results| {
        for (key, _, _) in results {
            key.key_stats(&mut stats)
        }
    });
    stats
}

pub fn print_stats(tcx: TyCtxt<'_>) {
    let queries = query_stats(tcx);

    if cfg!(debug_assertions) {
        let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
        let results: usize = queries.iter().map(|s| s.entry_count).sum();
        println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
    }

    let mut query_key_sizes = queries.clone();
    query_key_sizes.sort_by_key(|q| q.key_size);
    println!("\nLarge query keys:");
    for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
        println!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
    }

    let mut query_value_sizes = queries.clone();
    query_value_sizes.sort_by_key(|q| q.value_size);
    println!("\nLarge query values:");
    for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
        println!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
    }

    if cfg!(debug_assertions) {
        let mut query_cache_hits = queries.clone();
        query_cache_hits.sort_by_key(|q| q.cache_hits);
        println!("\nQuery cache hits:");
        for q in query_cache_hits.iter().rev() {
            println!(
                "   {} - {} ({}%)",
                q.name,
                q.cache_hits,
                q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64
            );
        }
    }

    let mut query_value_count = queries.clone();
    query_value_count.sort_by_key(|q| q.entry_count);
    println!("\nQuery value count:");
    for q in query_value_count.iter().rev() {
        println!("   {} - {}", q.name, q.entry_count);
    }

    let mut def_id_density: Vec<_> =
        queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
    def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
    println!("\nLocal DefId density:");
    for q in def_id_density.iter().rev() {
        println!("   {} - {}", q.name, q.local_def_id_keys.unwrap());
    }
}

macro_rules! print_stats {
    (<$tcx:tt> $($category:tt {
        $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*
    },)*) => {
        fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
            let mut queries = Vec::new();

            $($(
                queries.push(stats::<queries::$name<'_>>(
                    stringify!($name),
                    &tcx.queries.$name,
                ));
            )*)*

            queries
        }
    }
}

rustc_query_append! { [print_stats!][<'tcx>] }
<|endoftext|>


<commit_before>/// Implements a group of intersectable items

use std::num::Float;
use super::primitive::{DistanceMeasure, Intersectable, Intersection, Hit, Ray, Sphere};

#[derive(Debug)]
pub enum Pair<T, G> {
    Item(T),
    Group(G),
}

/// A group with static dispatch on intersect calls, but dynamically allocated
/// array of items.
#[derive(Debug, Default)]
pub struct TypedGroup<T: Float, B: DistanceMeasure<T>, I: Intersectable<T>> {
    pub bound: B,
    pub children: Vec<Pair<I, TypedGroup<T, B, I>>>,
}

impl<T, B, I> Intersectable<T> for TypedGroup<T, B, I>
where T: Float, B: DistanceMeasure<T>, I: Intersectable<T> {
    fn intersect(&self, max_distance: T, ray: &Ray<T>) -> Intersection<T> {
        if self.bound.distance_from_ray(&ray) == Float::infinity() {
            return None
        }
        for item in self.children.iter() {
            let h = match *item {
                Pair::Item(ref v) => v.intersect(max_distance, &ray),
                Pair::Group(ref g) => g.intersect(max_distance, &ray),
            };
            if h.is_some() {
                return h;
            }
        }

        None
    }
}

pub type SphericalGroup<T> = TypedGroup<T, Sphere<T>, Sphere<T>>;

#[cfg(test)]
mod tests {
    extern crate test;

    use super::*;
    use super::super::primitive::Intersectable;
    use super::super::vec::Vector;
    use super::super::primitive::{Sphere, Ray};
    use std::default::Default;
    use std::num::Float;

    fn setup_group<T: Float + Default>() -> (Ray<T>, Ray<T>, Ray<T>, SphericalGroup<T>) {
        let s1 = Sphere {center: Default::default(),
                         radius: Float::one() };
        let mut s2: Sphere<T> = Default::default();
        let one = <T as Float>::one();
        s2.center.z = s2.radius * (one + one);

        let mut g: SphericalGroup<T> = Default::default();
        assert!(g.children.len() == 0);

        g.children.push(Pair::Item(s1));
        g.children.push(Pair::Item(s2));
        g.bound.radius = one + one + one; // Bigger than it needs to be !
        let g = g;  // strip mut

        // ray for sphere 1
        let mut r1: Ray<T> = Default::default();
        r1.pos.x = one + one;
        r1.dir.x = -one;
        let r1 = r1;

        // ray for sphere 2
        let mut r2 = r1;
        r2.pos.z = s2.center.z;
        let r2 = r2;

        // missing ray
        let mut r3 = r1;
        r3.dir.x = -r3.dir.x;
        let r3 = r3;

        (r1, r2, r3, g)
    }

    #[test]
    fn intersect() {
        let (r1, r2, r3, g) = setup_group::<f32>();

        // Intersect Rays
        for ray in [&r1, &r2].iter() {
            let ho = g.intersect(Float::infinity(), &ray);
            assert!(!ho.is_none());
            let h = ho.unwrap();
            assert_eq!(h.distance, 1.0f32);
            assert_eq!(h.pos.x, 1.0f32);
            assert_eq!(h.pos.z, 0.0f32);
        }

        assert!(g.intersect(Float::infinity(), &r3).is_none());
    }

    const ITERATIONS: usize = 10000;

    #[bench]
    fn bench_intersect(b: &mut test::Bencher) {
        let (r1, r2, r3, g) = setup_group::<f32>();
        b.iter(|| {
            for _ in range(0, ITERATIONS) {
                test::black_box(g.intersect(Float::infinity(), &r1));
                test::black_box(g.intersect(Float::infinity(), &r2));
                test::black_box(g.intersect(Float::infinity(), &r3));
            }
        });
        b.bytes += (ITERATIONS * 3us) as u64;
    }

}
<commit_msg>Intermediate commit - about to remove unused code<commit_after>/// Implements a group of intersectable items

use std::num::Float;
use super::vec::Vector;
use std::default::Default;
use std::fmt::Debug;
use super::primitive::{DistanceMeasure, Intersectable, Intersection, Hit, Ray, Sphere};

#[derive(Debug)]
pub enum Pair<I, G> {
    Item(I),
    Group(G),
}

type TypedGroupPair<T, B, I> = Pair<I, TypedGroup<T, B, I>>;

/// A group with static dispatch on intersect calls, but dynamically allocated
/// array of items.
#[derive(Debug, Default)]
pub struct TypedGroup<T, B, I> {
    pub bound: B,
    pub children: Vec<TypedGroupPair<T, B, I>>,
}

// Separating the generator will work, but will also make everything so much more complicated !
// Can be done as an excersise later, once there is an image to render and to review
// fn generate_pyramidal_positions<T, F>(l: u32, p: &Vector<T>, r: T, f: F)
//     where T: Float, F: Fn(u32, T, Vector<T>) {
//     f(l, r, p)
//     if level == 1 {
//         return
//     }
//     let i: 0us;

// }

/// It's interesting that 'type' is indeed a new type, and not a type-def ! At least
/// when used in this situation !!!
impl<T> SphericalGroup<T>
    where T: Float + Default + Debug {

    // fn pyramid_recursive(level: u32, origin: &Vector<T>, radius: T) -> TypedGroupPair<T, B, I> {
    //     let g: TypedGroup<T, B, I> = Default::default();
    // }

    pub fn pyramid(level: u32, origin: &Vector<T>, radius: T) -> SphericalGroup<T> {
        let g: SphericalGroup<T> = Default::default();
        g
    }
    // pub fn pyramid() {

    // }
}

impl<T, B, I> Intersectable<T> for TypedGroup<T, B, I>
where T: Float, B: DistanceMeasure<T>, I: Intersectable<T> {
    fn intersect(&self, max_distance: T, ray: &Ray<T>) -> Intersection<T> {
        if self.bound.distance_from_ray(&ray) == Float::infinity() {
            return None
        }
        for item in self.children.iter() {
            let h = match *item {
                Pair::Item(ref v) => v.intersect(max_distance, &ray),
                Pair::Group(ref g) => g.intersect(max_distance, &ray),
            };
            if h.is_some() {
                return h;
            }
        }

        None
    }
}

pub type SphericalGroup<T> = TypedGroup<T, Sphere<T>, Sphere<T>>;

#[cfg(test)]
mod tests {
    extern crate test;

    use super::*;
    use super::super::primitive::Intersectable;
    use super::super::vec::Vector;
    use super::super::primitive::{Sphere, Ray};
    use std::default::Default;
    use std::num::Float;

    fn setup_group<T: Float + Default>() -> (Ray<T>, Ray<T>, Ray<T>, SphericalGroup<T>) {
        let s1 = Sphere {center: Default::default(),
                         radius: Float::one() };
        let mut s2: Sphere<T> = Default::default();
        let one = <T as Float>::one();
        s2.center.z = s2.radius * (one + one);

        let mut g: SphericalGroup<T> = Default::default();
        assert!(g.children.len() == 0);

        g.children.push(Pair::Item(s1));
        g.children.push(Pair::Item(s2));
        g.bound.radius = one + one + one; // Bigger than it needs to be !
        let g = g;  // strip mut

        // ray for sphere 1
        let mut r1: Ray<T> = Default::default();
        r1.pos.x = one + one;
        r1.dir.x = -one;
        let r1 = r1;

        // ray for sphere 2
        let mut r2 = r1;
        r2.pos.z = s2.center.z;
        let r2 = r2;

        // missing ray
        let mut r3 = r1;
        r3.dir.x = -r3.dir.x;
        let r3 = r3;

        (r1, r2, r3, g)
    }

    #[test]
    fn intersect() {
        let (r1, r2, r3, g) = setup_group::<f32>();

        // Intersect Rays
        for ray in [&r1, &r2].iter() {
            let ho = g.intersect(Float::infinity(), &ray);
            assert!(!ho.is_none());
            let h = ho.unwrap();
            assert_eq!(h.distance, 1.0f32);
            assert_eq!(h.pos.x, 1.0f32);
            assert_eq!(h.pos.z, 0.0f32);
        }

        assert!(g.intersect(Float::infinity(), &r3).is_none());
    }

    #[test]
    fn pyramid() {
        // let g = SphericalGroup::<f32> {bound: Default::default(), children: Default::default()};
        // For some reason, this doesn't resolve the name
        let g = SphericalGroup::<f32>::pyramid(8, &Vector { x: 1.0f32,
                                                            y: -1.0f32,
                                                            z: 0.0f32 }, 1.0);
        // let g: SphericalGroup<f32> = TypedGroup::pyramid(8, &Vector { x: 1.0f32,
        //                                                              y: -1.0f32,
        //                                                              z: 0.0f32 }, 1.0);
        // This also works, of course, but is less readable !
        // let g = TypedGroup::<f32, Sphere<f32>, Sphere<f32>>::pyramid(8, &Vector { x: 1.0f32,
        //                                                                          y: -1.0f32,
        //                                                                          z: 0.0f32 },
        //                                                                          1.0);

        assert!(g.children.len() > 0);

    }

    const ITERATIONS: usize = 10000;

    #[bench]
    fn bench_intersect(b: &mut test::Bencher) {
        let (r1, r2, r3, g) = setup_group::<f32>();
        b.iter(|| {
            for _ in range(0, ITERATIONS) {
                test::black_box(g.intersect(Float::infinity(), &r1));
                test::black_box(g.intersect(Float::infinity(), &r2));
                test::black_box(g.intersect(Float::infinity(), &r3));
            }
        });
        b.bytes += (ITERATIONS * 3us) as u64;
    }

}
<|endoftext|>


<commit_before>use crate::utils::sugg::Sugg;
use crate::utils::{
    differing_macro_contexts, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty, SpanlessEq,
};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;

declare_clippy_lint! {
    /// **What it does:** Checks for manual swapping.
    ///
    /// **Why is this bad?** The `std::mem::swap` function exposes the intent better
    /// without deinitializing or copying either variable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let mut a = 42;
    /// let mut b = 1337;
    ///
    /// let t = b;
    /// b = a;
    /// a = t;
    /// ```
    /// Use std::mem::swap():
    /// ```rust
    /// let mut a = 1;
    /// let mut b = 2;
    /// std::mem::swap(&mut a, &mut b);
    /// ```
    pub MANUAL_SWAP,
    complexity,
    "manual swap of two variables"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `foo = bar; bar = foo` sequences.
    ///
    /// **Why is this bad?** This looks like a failed attempt to swap.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let mut a = 1;
    /// # let mut b = 2;
    /// a = b;
    /// b = a;
    /// ```
    /// Could be written as:
    /// ```rust
    /// # let mut a = 1;
    /// # let mut b = 2;
    /// std::mem::swap(&mut a, &mut b);
    /// ```
    pub ALMOST_SWAPPED,
    correctness,
    "`foo = bar; bar = foo` sequence"
}

declare_lint_pass!(Swap => [MANUAL_SWAP, ALMOST_SWAPPED]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap {
    fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
        check_manual_swap(cx, block);
        check_suspicious_swap(cx, block);
    }
}

/// Implementation of the `MANUAL_SWAP` lint.
fn check_manual_swap(cx: &LateContext<'_, '_>, block: &Block) {
    for w in block.stmts.windows(3) {
        if_chain! {
            // let t = foo();
            if let StmtKind::Local(ref tmp) = w[0].node;
            if let Some(ref tmp_init) = tmp.init;
            if let PatKind::Binding(.., ident, None) = tmp.pat.node;

            // foo() = bar();
            if let StmtKind::Semi(ref first) = w[1].node;
            if let ExprKind::Assign(ref lhs1, ref rhs1) = first.node;

            // bar() = t;
            if let StmtKind::Semi(ref second) = w[2].node;
            if let ExprKind::Assign(ref lhs2, ref rhs2) = second.node;
            if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.node;
            if rhs2.segments.len() == 1;

            if ident.as_str() == rhs2.segments[0].ident.as_str();
            if SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1);
            if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2);
            then {
                fn check_for_slice<'a>(
                    cx: &LateContext<'_, '_>,
                    lhs1: &'a Expr,
                    lhs2: &'a Expr,
                ) -> Option<(&'a Expr, &'a Expr, &'a Expr)> {
                    if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.node {
                        if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.node {
                            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
                                let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1));

                                if matches!(ty.sty, ty::Slice(_)) ||
                                    matches!(ty.sty, ty::Array(_, _)) ||
                                    match_type(cx, ty, &paths::VEC) ||
                                    match_type(cx, ty, &paths::VEC_DEQUE) {
                                        return Some((lhs1, idx1, idx2));
                                }
                            }
                        }
                    }

                    None
                }

                let (replace, what, sugg) = if let Some((slice, idx1, idx2)) = check_for_slice(cx, lhs1, lhs2) {
                    if let Some(slice) = Sugg::hir_opt(cx, slice) {
                        (false,
                         format!(" elements of `{}`", slice),
                         format!("{}.swap({}, {})",
                                 slice.maybe_par(),
                                 snippet(cx, idx1.span, ".."),
                                 snippet(cx, idx2.span, "..")))
                    } else {
                        (false, String::new(), String::new())
                    }
                } else if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs1), Sugg::hir_opt(cx, rhs1)) {
                    (true, format!(" `{}` and `{}`", first, second),
                        format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()))
                } else {
                    (true, String::new(), String::new())
                };

                let span = w[0].span.to(second.span);

                span_lint_and_then(cx,
                                   MANUAL_SWAP,
                                   span,
                                   &format!("this looks like you are swapping{} manually", what),
                                   |db| {
                                       if !sugg.is_empty() {
                                           db.span_suggestion(
                                               span,
                                               "try",
                                               sugg,
                                               Applicability::Unspecified,
                                           );

                                           if replace {
                                               db.note("or maybe you should use `std::mem::replace`?");
                                           }
                                       }
                                   });
            }
        }
    }
}

/// Implementation of the `ALMOST_SWAPPED` lint.
fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
    for w in block.stmts.windows(2) {
        if_chain! {
            if let StmtKind::Semi(ref first) = w[0].node;
            if let StmtKind::Semi(ref second) = w[1].node;
            if !differing_macro_contexts(first.span, second.span);
            if let ExprKind::Assign(ref lhs0, ref rhs0) = first.node;
            if let ExprKind::Assign(ref lhs1, ref rhs1) = second.node;
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1);
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0);
            then {
                let lhs0 = Sugg::hir_opt(cx, lhs0);
                let rhs0 = Sugg::hir_opt(cx, rhs0);
                let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
                    (
                        format!(" `{}` and `{}`", first, second),
                        first.mut_addr().to_string(),
                        second.mut_addr().to_string(),
                    )
                } else {
                    (String::new(), String::new(), String::new())
                };

                let span = first.span.to(second.span);

                span_lint_and_then(cx,
                                   ALMOST_SWAPPED,
                                   span,
                                   &format!("this looks like you are trying to swap{}", what),
                                   |db| {
                                       if !what.is_empty() {
                                           db.span_suggestion(
                                               span,
                                               "try",
                                               format!(
                                                   "std::mem::swap({}, {})",
                                                   lhs,
                                                   rhs,
                                               ),
                                               Applicability::MaybeIncorrect,
                                           );
                                           db.note("or maybe you should use `std::mem::replace`?");
                                       }
                                   });
            }
        }
    }
}
<commit_msg>Fix incorrect swap suggestion<commit_after>use crate::utils::sugg::Sugg;
use crate::utils::{
    differing_macro_contexts, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty, SpanlessEq,
};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;

declare_clippy_lint! {
    /// **What it does:** Checks for manual swapping.
    ///
    /// **Why is this bad?** The `std::mem::swap` function exposes the intent better
    /// without deinitializing or copying either variable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let mut a = 42;
    /// let mut b = 1337;
    ///
    /// let t = b;
    /// b = a;
    /// a = t;
    /// ```
    /// Use std::mem::swap():
    /// ```rust
    /// let mut a = 1;
    /// let mut b = 2;
    /// std::mem::swap(&mut a, &mut b);
    /// ```
    pub MANUAL_SWAP,
    complexity,
    "manual swap of two variables"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `foo = bar; bar = foo` sequences.
    ///
    /// **Why is this bad?** This looks like a failed attempt to swap.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let mut a = 1;
    /// # let mut b = 2;
    /// a = b;
    /// b = a;
    /// ```
    /// Could be written as:
    /// ```rust
    /// # let mut a = 1;
    /// # let mut b = 2;
    /// std::mem::swap(&mut a, &mut b);
    /// ```
    pub ALMOST_SWAPPED,
    correctness,
    "`foo = bar; bar = foo` sequence"
}

declare_lint_pass!(Swap => [MANUAL_SWAP, ALMOST_SWAPPED]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap {
    fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
        check_manual_swap(cx, block);
        check_suspicious_swap(cx, block);
    }
}

/// Implementation of the `MANUAL_SWAP` lint.
fn check_manual_swap(cx: &LateContext<'_, '_>, block: &Block) {
    for w in block.stmts.windows(3) {
        if_chain! {
            // let t = foo();
            if let StmtKind::Local(ref tmp) = w[0].node;
            if let Some(ref tmp_init) = tmp.init;
            if let PatKind::Binding(.., ident, None) = tmp.pat.node;

            // foo() = bar();
            if let StmtKind::Semi(ref first) = w[1].node;
            if let ExprKind::Assign(ref lhs1, ref rhs1) = first.node;

            // bar() = t;
            if let StmtKind::Semi(ref second) = w[2].node;
            if let ExprKind::Assign(ref lhs2, ref rhs2) = second.node;
            if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.node;
            if rhs2.segments.len() == 1;

            if ident.as_str() == rhs2.segments[0].ident.as_str();
            if SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1);
            if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2);
            then {
                fn check_for_slice<'a>(
                    cx: &LateContext<'_, '_>,
                    lhs1: &'a Expr,
                    lhs2: &'a Expr,
                ) -> Option<(&'a Expr, &'a Expr, &'a Expr)> {
                    if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.node {
                        if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.node {
                            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
                                let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1));

                                if matches!(ty.sty, ty::Slice(_)) ||
                                    matches!(ty.sty, ty::Array(_, _)) ||
                                    match_type(cx, ty, &paths::VEC) ||
                                    match_type(cx, ty, &paths::VEC_DEQUE) {
                                        return Some((lhs1, idx1, idx2));
                                }
                            }
                        }
                    }

                    None
                }

                if let ExprKind::Field(ref lhs1, _) = lhs1.node {
                    if let ExprKind::Field(ref lhs2, _) = lhs2.node {
                        if lhs1.hir_id.owner_def_id() == lhs2.hir_id.owner_def_id() {
                            return;
                        }
                    }
                }

                let (replace, what, sugg) = if let Some((slice, idx1, idx2)) = check_for_slice(cx, lhs1, lhs2) {
                    if let Some(slice) = Sugg::hir_opt(cx, slice) {
                        (false,
                         format!(" elements of `{}`", slice),
                         format!("{}.swap({}, {})",
                                 slice.maybe_par(),
                                 snippet(cx, idx1.span, ".."),
                                 snippet(cx, idx2.span, "..")))
                    } else {
                        (false, String::new(), String::new())
                    }
                } else if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs1), Sugg::hir_opt(cx, rhs1)) {
                    (true, format!(" `{}` and `{}`", first, second),
                        format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()))
                } else {
                    (true, String::new(), String::new())
                };

                let span = w[0].span.to(second.span);

                span_lint_and_then(cx,
                                   MANUAL_SWAP,
                                   span,
                                   &format!("this looks like you are swapping{} manually", what),
                                   |db| {
                                       if !sugg.is_empty() {
                                           db.span_suggestion(
                                               span,
                                               "try",
                                               sugg,
                                               Applicability::Unspecified,
                                           );

                                           if replace {
                                               db.note("or maybe you should use `std::mem::replace`?");
                                           }
                                       }
                                   });
            }
        }
    }
}

/// Implementation of the `ALMOST_SWAPPED` lint.
fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
    for w in block.stmts.windows(2) {
        if_chain! {
            if let StmtKind::Semi(ref first) = w[0].node;
            if let StmtKind::Semi(ref second) = w[1].node;
            if !differing_macro_contexts(first.span, second.span);
            if let ExprKind::Assign(ref lhs0, ref rhs0) = first.node;
            if let ExprKind::Assign(ref lhs1, ref rhs1) = second.node;
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1);
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0);
            then {
                let lhs0 = Sugg::hir_opt(cx, lhs0);
                let rhs0 = Sugg::hir_opt(cx, rhs0);
                let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
                    (
                        format!(" `{}` and `{}`", first, second),
                        first.mut_addr().to_string(),
                        second.mut_addr().to_string(),
                    )
                } else {
                    (String::new(), String::new(), String::new())
                };

                let span = first.span.to(second.span);

                span_lint_and_then(cx,
                                   ALMOST_SWAPPED,
                                   span,
                                   &format!("this looks like you are trying to swap{}", what),
                                   |db| {
                                       if !what.is_empty() {
                                           db.span_suggestion(
                                               span,
                                               "try",
                                               format!(
                                                   "std::mem::swap({}, {})",
                                                   lhs,
                                                   rhs,
                                               ),
                                               Applicability::MaybeIncorrect,
                                           );
                                           db.note("or maybe you should use `std::mem::replace`?");
                                       }
                                   });
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::result::Result;

use {action, config, context, Message, MiliSec, Response};
use condition::Condition;
use context::base::BaseContextBuilder;
use context::{Context};
use context::linear::LinearContext;
use context::map::MapContext;
use dispatcher::request::{InternalRequest, Request};
use dispatcher::reactor::RequestReactor;
use dispatcher::{ResponseSender, ResponseHandler};
use dispatcher::response;
use dispatcher::demux::Demultiplexer;
use dispatcher::handlers;
pub use self::error::Error;
use reactor::{Event, EventHandler, Reactor};
use timer::Timer;

const TIMER_STEP: MiliSec = 100;

use self::exit_handler::ExitHandler;

pub mod error;
mod exit_handler;
#[cfg(test)]
mod test;

pub struct Correlator {
    dispatcher_input_channel: mpsc::Sender<Request<Message>>,
    dispatcher_output_channel: mpsc::Receiver<Response>,
    dispatcher_thread_handle: thread::JoinHandle<()>,
    handlers: HashMap<ResponseHandler, Box<EventHandler<Response>>>
}

fn create_context(config_context: config::Context, response_sender: Rc<RefCell<Box<response::ResponseSender<Response>>>>) -> Context {
    let config::Context{name, uuid, conditions, context_id, actions} = config_context;
    let mut boxed_actions = Vec::new();

    for i in actions.into_iter() {
        let action = action::from_config(i, response_sender.clone());
        boxed_actions.push(action);
    }
    let base = BaseContextBuilder::new(uuid, conditions);
    let base = base.name(name);
    let base = base.actions(boxed_actions);
    let base = base.build();
    if let Some(context_id) = context_id {
        Context::Map(MapContext::new(base, context_id))
    } else {
        Context::Linear(LinearContext::from(base))
    }
}

fn create_event_handlers(contexts: Vec<config::Context>, response_sender: Rc<RefCell<Box<response::ResponseSender<Response>>>>) -> Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>> {
    let mut event_handlers = Vec::new();
    for i in contexts.into_iter() {
        let context: context::Context = create_context(i, response_sender.clone());
        let event_handler: Box<context::event::EventHandler<InternalRequest>> = context.into();
        let handler = Rc::new(RefCell::new(event_handler));
        event_handlers.push(handler);
    }
    event_handlers
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let (dispatcher_output_channel_tx, dispatcher_output_channel_rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            let dmux = Demultiplexer::new(rx);
            let exit_condition = Condition::new(false);
            let mut reactor = RequestReactor::new(dmux, exit_condition.clone());
            let response_sender = Box::new(ResponseSender::new(dispatcher_output_channel_tx)) as Box<response::ResponseSender<Response>>;
            let response_sender = Rc::new(RefCell::new(response_sender));

            let exit_handler = Box::new(handlers::exit::ExitEventHandler::new(exit_condition, response_sender.clone()));
            let mut timer_event_handler = Box::new(handlers::timer::TimerEventHandler::new());
            let mut message_event_handler = Box::new(handlers::message::MessageEventHandler::new());

            let event_handlers = create_event_handlers(contexts, response_sender);

            for i in event_handlers {
                timer_event_handler.register_handler(i.clone());
                message_event_handler.register_handler(i.clone())
            }

            reactor.register_handler(exit_handler);
            reactor.register_handler(timer_event_handler);
            reactor.register_handler(message_event_handler);
            reactor.handle_events();
        });

        Correlator {
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_output_channel: dispatcher_output_channel_rx,
            dispatcher_thread_handle: handle,
            handlers: HashMap::new()
        }
    }

    pub fn register_handler(&mut self, handler: Box<EventHandler<Response>>) {
        self.handlers.insert(handler.handler(), handler);
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Request<Message>>> {
        self.handle_events();
        self.dispatcher_input_channel.send(Request::Message(message))
    }

    fn handle_event(&mut self, event: Response) {
        if let Some(handler) = self.handlers.get_mut(&event.handler()) {
            handler.handle_event(event);
        } else {
            trace!("no event handler found for handling a Response");
        }
    }

    pub fn handle_events(&mut self) {
        for i in self.dispatcher_output_channel.try_recv() {
            self.handle_event(i);
        }
    }

    pub fn stop(mut self) -> thread::Result<()> {
        self.handle_events();
        self.stop_dispatcher();
        self.dispatcher_thread_handle.join()
    }

    fn stop_dispatcher(&mut self) {
        let exit_condition = Condition::new(false);
        let exit_handler = Box::new(ExitHandler::new(exit_condition.clone(), self.dispatcher_input_channel.clone()));
        self.register_handler(exit_handler);
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        while !exit_condition.is_active() {
            if let Ok(event) = self.dispatcher_output_channel.recv() {
                self.handle_event(event);
            }
        }
    }
}
<commit_msg>Correlator: add from_path() method<commit_after>use serde_json::from_str;
use std::cell::RefCell;
use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::result::Result;

use {action, config, context, Message, MiliSec, Response};
use condition::Condition;
use context::base::BaseContextBuilder;
use context::{Context};
use context::linear::LinearContext;
use context::map::MapContext;
use dispatcher::request::{InternalRequest, Request};
use dispatcher::reactor::RequestReactor;
use dispatcher::{ResponseSender, ResponseHandler};
use dispatcher::response;
use dispatcher::demux::Demultiplexer;
use dispatcher::handlers;
pub use self::error::Error;
use reactor::{Event, EventHandler, Reactor};
use timer::Timer;

const TIMER_STEP: MiliSec = 100;

use self::exit_handler::ExitHandler;

pub mod error;
mod exit_handler;
#[cfg(test)]
mod test;

pub struct Correlator {
    dispatcher_input_channel: mpsc::Sender<Request<Message>>,
    dispatcher_output_channel: mpsc::Receiver<Response>,
    dispatcher_thread_handle: thread::JoinHandle<()>,
    handlers: HashMap<ResponseHandler, Box<EventHandler<Response>>>
}

fn create_context(config_context: config::Context, response_sender: Rc<RefCell<Box<response::ResponseSender<Response>>>>) -> Context {
    let config::Context{name, uuid, conditions, context_id, actions} = config_context;
    let mut boxed_actions = Vec::new();

    for i in actions.into_iter() {
        let action = action::from_config(i, response_sender.clone());
        boxed_actions.push(action);
    }
    let base = BaseContextBuilder::new(uuid, conditions);
    let base = base.name(name);
    let base = base.actions(boxed_actions);
    let base = base.build();
    if let Some(context_id) = context_id {
        Context::Map(MapContext::new(base, context_id))
    } else {
        Context::Linear(LinearContext::from(base))
    }
}

fn create_event_handlers(contexts: Vec<config::Context>, response_sender: Rc<RefCell<Box<response::ResponseSender<Response>>>>) -> Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>> {
    let mut event_handlers = Vec::new();
    for i in contexts.into_iter() {
        let context: context::Context = create_context(i, response_sender.clone());
        let event_handler: Box<context::event::EventHandler<InternalRequest>> = context.into();
        let handler = Rc::new(RefCell::new(event_handler));
        event_handlers.push(handler);
    }
    event_handlers
}

impl Correlator {
    pub fn from_path(path: &str) -> Result<Correlator, Error> {
        let mut file = try!(File::open(path));
        let mut buffer = String::new();
        try!(file.read_to_string(&mut buffer));
        let contexts = try!(from_str::<Vec<config::Context>>(&buffer));
        Ok(Correlator::new(contexts))
    }

    pub fn new(contexts: Vec<config::Context>) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let (dispatcher_output_channel_tx, dispatcher_output_channel_rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            let dmux = Demultiplexer::new(rx);
            let exit_condition = Condition::new(false);
            let mut reactor = RequestReactor::new(dmux, exit_condition.clone());
            let response_sender = Box::new(ResponseSender::new(dispatcher_output_channel_tx)) as Box<response::ResponseSender<Response>>;
            let response_sender = Rc::new(RefCell::new(response_sender));

            let exit_handler = Box::new(handlers::exit::ExitEventHandler::new(exit_condition, response_sender.clone()));
            let mut timer_event_handler = Box::new(handlers::timer::TimerEventHandler::new());
            let mut message_event_handler = Box::new(handlers::message::MessageEventHandler::new());

            let event_handlers = create_event_handlers(contexts, response_sender);

            for i in event_handlers {
                timer_event_handler.register_handler(i.clone());
                message_event_handler.register_handler(i.clone())
            }

            reactor.register_handler(exit_handler);
            reactor.register_handler(timer_event_handler);
            reactor.register_handler(message_event_handler);
            reactor.handle_events();
        });

        Correlator {
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_output_channel: dispatcher_output_channel_rx,
            dispatcher_thread_handle: handle,
            handlers: HashMap::new()
        }
    }

    pub fn register_handler(&mut self, handler: Box<EventHandler<Response>>) {
        self.handlers.insert(handler.handler(), handler);
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Request<Message>>> {
        self.handle_events();
        self.dispatcher_input_channel.send(Request::Message(message))
    }

    fn handle_event(&mut self, event: Response) {
        if let Some(handler) = self.handlers.get_mut(&event.handler()) {
            handler.handle_event(event);
        } else {
            trace!("no event handler found for handling a Response");
        }
    }

    pub fn handle_events(&mut self) {
        for i in self.dispatcher_output_channel.try_recv() {
            self.handle_event(i);
        }
    }

    pub fn stop(mut self) -> thread::Result<()> {
        self.handle_events();
        self.stop_dispatcher();
        self.dispatcher_thread_handle.join()
    }

    fn stop_dispatcher(&mut self) {
        let exit_condition = Condition::new(false);
        let exit_handler = Box::new(ExitHandler::new(exit_condition.clone(), self.dispatcher_input_channel.clone()));
        self.register_handler(exit_handler);
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        while !exit_condition.is_active() {
            if let Ok(event) = self.dispatcher_output_channel.recv() {
                self.handle_event(event);
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod control_regs;
pub mod descriptor;
pub mod dtables;
pub mod io;
pub mod irq;
pub mod msr;
pub mod paging;
pub mod flags;
pub mod segmentation;
pub mod task;
pub mod tlb;

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum PrivilegeLevel {
    Ring0 = 0,
    Ring1 = 1,
    Ring2 = 2,
    Ring3 = 3,
}

#[inline(always)]
pub unsafe fn halt() {
    asm!("hlt" :::: "volatile", "intel");
}
<commit_msg>Remove unnecessary intel qualifier from asm!().<commit_after>pub mod control_regs;
pub mod descriptor;
pub mod dtables;
pub mod io;
pub mod irq;
pub mod msr;
pub mod paging;
pub mod flags;
pub mod segmentation;
pub mod task;
pub mod tlb;

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum PrivilegeLevel {
    Ring0 = 0,
    Ring1 = 1,
    Ring2 = 2,
    Ring3 = 3,
}

#[inline(always)]
pub unsafe fn halt() {
    asm!("hlt" :::: "volatile");
}
<|endoftext|>


<commit_before>use super::placement::sm::client::SMClient;
use bifrost::rpc::*;
use bifrost_plugins::hash_ident;
use client::AsyncClient;
use dovahkiin::types::custom_types::id::Id;
use index::btree::storage::store_changed_nodes;
use index::lsmtree::service::inner::LSMTreeIns;
use index::lsmtree::split::check_and_split;
use index::lsmtree::tree::{LSMTree, LSMTreeResult};
use index::{EntryKey, Ordering};
use itertools::Itertools;
use parking_lot::RwLock;
use rayon::iter::IntoParallelRefIterator;
use rayon::iter::ParallelIterator;
use server::NebServer;
use smallvec::SmallVec;
use std::collections::HashMap;
use std::path::Component::CurDir;
use std::sync::atomic;
use std::sync::atomic::AtomicU64;
use std::thread;

mod inner;
#[cfg(test)]
mod test;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(LSM_TREE_RPC_SERVICE) as u64;

#[derive(Serialize, Deserialize, Debug)]
pub enum LSMTreeSvrError {
    TreeNotFound,
    SMError,
}

#[derive(Serialize, Deserialize)]
pub struct LSMTreeSummary {
    id: Id,
    count: u64,
    epoch: u64,
    range: (Vec<u8>, Vec<u8>),
}

service! {
    rpc seek(tree_id: Id, key: Vec<u8>, ordering: Ordering, epoch: u64) -> LSMTreeResult<u64> | LSMTreeSvrError;
    rpc next(tree_id: Id, cursor_id: u64) -> Option<bool> | LSMTreeSvrError;
    rpc current(tree_id: Id, cursor_id: u64) -> Option<Option<Vec<u8>>> | LSMTreeSvrError;
    rpc complete(tree_id: Id, cursor_id: u64) -> bool | LSMTreeSvrError;
    rpc new_tree(start: Vec<u8>, end: Vec<u8>, id: Id) -> bool;
    rpc summary() -> Vec<LSMTreeSummary>;

    rpc insert(tree_id: Id, key: Vec<u8>, epoch: u64) -> LSMTreeResult<bool> | LSMTreeSvrError;
    rpc merge(tree_id: Id, keys: Vec<Vec<u8>>, epoch: u64) -> LSMTreeResult<()> | LSMTreeSvrError;
    rpc set_epoch(tree_id: Id, epoch: u64) -> u64 | LSMTreeSvrError;
}

pub struct LSMTreeService {
    neb_server: Arc<NebServer>,
    sm: Arc<SMClient>,
    counter: AtomicU64,
    trees: Arc<RwLock<HashMap<Id, Arc<LSMTreeIns>>>>,
}

dispatch_rpc_service_functions!(LSMTreeService);

impl Service for LSMTreeService {
    fn seek(
        &self,
        tree_id: Id,
        key: Vec<u8>,
        ordering: Ordering,
        epoch: u64,
    ) -> Box<Future<Item = LSMTreeResult<u64>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| {
                    tree.with_epoch_check(epoch, || tree.seek(&SmallVec::from(key), ordering))
                }),
        )
    }

    fn next(
        &self,
        tree_id: Id,
        cursor_id: u64,
    ) -> Box<Future<Item = Option<bool>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.next(&cursor_id)),
        )
    }

    fn current(
        &self,
        tree_id: Id,
        cursor_id: u64,
    ) -> Box<Future<Item = Option<Option<Vec<u8>>>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.current(&cursor_id)),
        )
    }

    fn complete(
        &self,
        tree_id: Id,
        cursor_id: u64,
    ) -> Box<Future<Item = bool, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.complete(&cursor_id)),
        )
    }

    fn new_tree(
        &self,
        start: Vec<u8>,
        end: Vec<u8>,
        id: Id,
    ) -> Box<Future<Item = bool, Error = ()>> {
        let mut trees = self.trees.write();
        let succeed = if trees.contains_key(&id) {
            false
        } else {
            trees.insert(
                id,
                Arc::new(LSMTreeIns::new(
                    (EntryKey::from(start), EntryKey::from(end)),
                    id,
                )),
            );
            true
        };
        box persist(self.neb_server.clone(), succeed)
    }

    fn summary(&self) -> Box<Future<Item = Vec<LSMTreeSummary>, Error = ()>> {
        let trees = self.trees.read();
        box future::ok(
            trees
                .iter()
                .map(|(id, tree)| LSMTreeSummary {
                    id: *id,
                    count: tree.count(),
                    epoch: tree.epoch(),
                    range: tree.range(),
                })
                .sorted_by_key(|tree| tree.range.0.clone())
                .collect(),
        )
    }

    fn insert(
        &self,
        tree_id: Id,
        key: Vec<u8>,
        epoch: u64,
    ) -> Box<Future<Item = LSMTreeResult<bool>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        let neb = self.neb_server.clone();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.with_epoch_check(epoch, || tree.insert(SmallVec::from(key)))),
        )
        .and_then(|o| persist(neb, o))
    }

    fn merge(
        &self,
        tree_id: Id,
        keys: Vec<Vec<u8>>,
        epoch: u64,
    ) -> Box<Future<Item = LSMTreeResult<()>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        let neb = self.neb_server.clone();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| {
                    tree.with_epoch_check(epoch, || {
                        tree.merge(box keys.into_iter().map(|key| SmallVec::from(key)).collect())
                    })
                }),
        )
        .and_then(|o| persist(neb, o))
    }

    fn set_epoch(
        &self,
        tree_id: Id,
        epoch: u64,
    ) -> Box<Future<Item = u64, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        let sm = self.sm.clone();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.set_epoch(epoch)),
        )
        .and_then(move |_| {
            sm.update_epoch(&tree_id, &epoch)
                .map_err(|_| LSMTreeSvrError::SMError)
                .and_then(|r| r.map_err(|_| LSMTreeSvrError::SMError))
        })
    }
}

impl LSMTreeService {
    pub fn new(neb_server: &Arc<NebServer>, sm: &Arc<SMClient>) -> Arc<Self> {
        let trees = Arc::new(RwLock::new(HashMap::new()));
        let trees_clone = trees.clone();
        let neb = neb_server.clone();
        thread::Builder::new()
            .name("LSM-tree service sentinel".to_string())
            .spawn(move || {
                let tree_map = trees_clone.read();
                tree_map.values().cloned().collect_vec().par_iter().for_each(|tree: &Arc<LSMTreeIns>| {
                    tree.check_and_merge();
                });
                persist::<_, ()>(neb.clone(), ()).wait().unwrap()
            });
        Arc::new(Self {
            neb_server: neb_server.clone(),
            counter: AtomicU64::new(0),
            sm: sm.clone(),
            trees,
        })
    }
}

fn persist<T, E>(neb: Arc<NebServer>, val: T) -> impl Future<Item = T, Error = E> {
    store_changed_nodes(neb).then(move |_| future::ok(val))
}
<commit_msg>cargo fmt<commit_after>use super::placement::sm::client::SMClient;
use bifrost::rpc::*;
use bifrost_plugins::hash_ident;
use client::AsyncClient;
use dovahkiin::types::custom_types::id::Id;
use index::btree::storage::store_changed_nodes;
use index::lsmtree::service::inner::LSMTreeIns;
use index::lsmtree::split::check_and_split;
use index::lsmtree::tree::{LSMTree, LSMTreeResult};
use index::{EntryKey, Ordering};
use itertools::Itertools;
use parking_lot::RwLock;
use rayon::iter::IntoParallelRefIterator;
use rayon::iter::ParallelIterator;
use server::NebServer;
use smallvec::SmallVec;
use std::collections::HashMap;
use std::path::Component::CurDir;
use std::sync::atomic;
use std::sync::atomic::AtomicU64;
use std::thread;

mod inner;
#[cfg(test)]
mod test;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(LSM_TREE_RPC_SERVICE) as u64;

#[derive(Serialize, Deserialize, Debug)]
pub enum LSMTreeSvrError {
    TreeNotFound,
    SMError,
}

#[derive(Serialize, Deserialize)]
pub struct LSMTreeSummary {
    id: Id,
    count: u64,
    epoch: u64,
    range: (Vec<u8>, Vec<u8>),
}

service! {
    rpc seek(tree_id: Id, key: Vec<u8>, ordering: Ordering, epoch: u64) -> LSMTreeResult<u64> | LSMTreeSvrError;
    rpc next(tree_id: Id, cursor_id: u64) -> Option<bool> | LSMTreeSvrError;
    rpc current(tree_id: Id, cursor_id: u64) -> Option<Option<Vec<u8>>> | LSMTreeSvrError;
    rpc complete(tree_id: Id, cursor_id: u64) -> bool | LSMTreeSvrError;
    rpc new_tree(start: Vec<u8>, end: Vec<u8>, id: Id) -> bool;
    rpc summary() -> Vec<LSMTreeSummary>;

    rpc insert(tree_id: Id, key: Vec<u8>, epoch: u64) -> LSMTreeResult<bool> | LSMTreeSvrError;
    rpc merge(tree_id: Id, keys: Vec<Vec<u8>>, epoch: u64) -> LSMTreeResult<()> | LSMTreeSvrError;
    rpc set_epoch(tree_id: Id, epoch: u64) -> u64 | LSMTreeSvrError;
}

pub struct LSMTreeService {
    neb_server: Arc<NebServer>,
    sm: Arc<SMClient>,
    counter: AtomicU64,
    trees: Arc<RwLock<HashMap<Id, Arc<LSMTreeIns>>>>,
}

dispatch_rpc_service_functions!(LSMTreeService);

impl Service for LSMTreeService {
    fn seek(
        &self,
        tree_id: Id,
        key: Vec<u8>,
        ordering: Ordering,
        epoch: u64,
    ) -> Box<Future<Item = LSMTreeResult<u64>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| {
                    tree.with_epoch_check(epoch, || tree.seek(&SmallVec::from(key), ordering))
                }),
        )
    }

    fn next(
        &self,
        tree_id: Id,
        cursor_id: u64,
    ) -> Box<Future<Item = Option<bool>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.next(&cursor_id)),
        )
    }

    fn current(
        &self,
        tree_id: Id,
        cursor_id: u64,
    ) -> Box<Future<Item = Option<Option<Vec<u8>>>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.current(&cursor_id)),
        )
    }

    fn complete(
        &self,
        tree_id: Id,
        cursor_id: u64,
    ) -> Box<Future<Item = bool, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.complete(&cursor_id)),
        )
    }

    fn new_tree(
        &self,
        start: Vec<u8>,
        end: Vec<u8>,
        id: Id,
    ) -> Box<Future<Item = bool, Error = ()>> {
        let mut trees = self.trees.write();
        let succeed = if trees.contains_key(&id) {
            false
        } else {
            trees.insert(
                id,
                Arc::new(LSMTreeIns::new(
                    (EntryKey::from(start), EntryKey::from(end)),
                    id,
                )),
            );
            true
        };
        box persist(self.neb_server.clone(), succeed)
    }

    fn summary(&self) -> Box<Future<Item = Vec<LSMTreeSummary>, Error = ()>> {
        let trees = self.trees.read();
        box future::ok(
            trees
                .iter()
                .map(|(id, tree)| LSMTreeSummary {
                    id: *id,
                    count: tree.count(),
                    epoch: tree.epoch(),
                    range: tree.range(),
                })
                .sorted_by_key(|tree| tree.range.0.clone())
                .collect(),
        )
    }

    fn insert(
        &self,
        tree_id: Id,
        key: Vec<u8>,
        epoch: u64,
    ) -> Box<Future<Item = LSMTreeResult<bool>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        let neb = self.neb_server.clone();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.with_epoch_check(epoch, || tree.insert(SmallVec::from(key)))),
        )
        .and_then(|o| persist(neb, o))
    }

    fn merge(
        &self,
        tree_id: Id,
        keys: Vec<Vec<u8>>,
        epoch: u64,
    ) -> Box<Future<Item = LSMTreeResult<()>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        let neb = self.neb_server.clone();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| {
                    tree.with_epoch_check(epoch, || {
                        tree.merge(box keys.into_iter().map(|key| SmallVec::from(key)).collect())
                    })
                }),
        )
        .and_then(|o| persist(neb, o))
    }

    fn set_epoch(
        &self,
        tree_id: Id,
        epoch: u64,
    ) -> Box<Future<Item = u64, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        let sm = self.sm.clone();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.set_epoch(epoch)),
        )
        .and_then(move |_| {
            sm.update_epoch(&tree_id, &epoch)
                .map_err(|_| LSMTreeSvrError::SMError)
                .and_then(|r| r.map_err(|_| LSMTreeSvrError::SMError))
        })
    }
}

impl LSMTreeService {
    pub fn new(neb_server: &Arc<NebServer>, sm: &Arc<SMClient>) -> Arc<Self> {
        let trees = Arc::new(RwLock::new(HashMap::new()));
        let trees_clone = trees.clone();
        let neb = neb_server.clone();
        thread::Builder::new()
            .name("LSM-tree service sentinel".to_string())
            .spawn(move || {
                let tree_map = trees_clone.read();
                tree_map
                    .values()
                    .cloned()
                    .collect_vec()
                    .par_iter()
                    .for_each(|tree: &Arc<LSMTreeIns>| {
                        tree.check_and_merge();
                    });
                persist::<_, ()>(neb.clone(), ()).wait().unwrap()
            });
        Arc::new(Self {
            neb_server: neb_server.clone(),
            counter: AtomicU64::new(0),
            sm: sm.clone(),
            trees,
        })
    }
}

fn persist<T, E>(neb: Arc<NebServer>, val: T) -> impl Future<Item = T, Error = E> {
    store_changed_nodes(neb).then(move |_| future::ok(val))
}
<|endoftext|>


<commit_before><commit_msg>install_package().<commit_after>fn install_package(input: &str, base_path: &Path) -> Result<(), String> {

}<|endoftext|>