<commit_before>pub use self::Mode::*;

use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use test::ColorConfig;
use crate::util::PathBufExt;

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Mode {
    CompileFail,
    RunFail,
    /// This now behaves like a `ui` test that has an implict `// run-pass`.
    RunPass,
    RunPassValgrind,
    Pretty,
    DebugInfoBoth,
    DebugInfoGdb,
    DebugInfoLldb,
    Codegen,
    Rustdoc,
    CodegenUnits,
    Incremental,
    RunMake,
    Ui,
    JsDocTest,
    MirOpt,
    Assembly,
}

impl Mode {
    pub fn disambiguator(self) -> &'static str {
        // Run-pass and pretty run-pass tests could run concurrently, and if they do,
        // they need to keep their output segregated. Same is true for debuginfo tests that
        // can be run both on gdb and lldb.
        match self {
            Pretty => ".pretty",
            DebugInfoGdb => ".gdb",
            DebugInfoLldb => ".lldb",
            _ => "",
        }
    }
}

impl FromStr for Mode {
    type Err = ();
    fn from_str(s: &str) -> Result<Mode, ()> {
        match s {
            "compile-fail" => Ok(CompileFail),
            "run-fail" => Ok(RunFail),
            "run-pass" => Ok(RunPass),
            "run-pass-valgrind" => Ok(RunPassValgrind),
            "pretty" => Ok(Pretty),
            "debuginfo-both" => Ok(DebugInfoBoth),
            "debuginfo-lldb" => Ok(DebugInfoLldb),
            "debuginfo-gdb" => Ok(DebugInfoGdb),
            "codegen" => Ok(Codegen),
            "rustdoc" => Ok(Rustdoc),
            "codegen-units" => Ok(CodegenUnits),
            "incremental" => Ok(Incremental),
            "run-make" => Ok(RunMake),
            "ui" => Ok(Ui),
            "js-doc-test" => Ok(JsDocTest),
            "mir-opt" => Ok(MirOpt),
            "assembly" => Ok(Assembly),
            _ => Err(()),
        }
    }
}

impl fmt::Display for Mode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match *self {
            CompileFail => "compile-fail",
            RunFail => "run-fail",
            RunPass => "run-pass",
            RunPassValgrind => "run-pass-valgrind",
            Pretty => "pretty",
            DebugInfoBoth => "debuginfo-both",
            DebugInfoGdb => "debuginfo-gdb",
            DebugInfoLldb => "debuginfo-lldb",
            Codegen => "codegen",
            Rustdoc => "rustdoc",
            CodegenUnits => "codegen-units",
            Incremental => "incremental",
            RunMake => "run-make",
            Ui => "ui",
            JsDocTest => "js-doc-test",
            MirOpt => "mir-opt",
            Assembly => "assembly",
        };
        fmt::Display::fmt(s, f)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum CompareMode {
    Nll,
    Polonius,
}

impl CompareMode {
    pub(crate) fn to_str(&self) -> &'static str {
        match *self {
            CompareMode::Nll => "nll",
            CompareMode::Polonius => "polonius",
        }
    }

    pub fn parse(s: String) -> CompareMode {
        match s.as_str() {
            "nll" => CompareMode::Nll,
            "polonius" => CompareMode::Polonius,
            x => panic!("unknown --compare-mode option: {}", x),
        }
    }
}

#[derive(Clone)]
pub struct Config {
    /// `true` to to overwrite stderr/stdout files instead of complaining about changes in output.
    pub bless: bool,

    /// The library paths required for running the compiler.
    pub compile_lib_path: PathBuf,

    /// The library paths required for running compiled programs.
    pub run_lib_path: PathBuf,

    /// The rustc executable.
    pub rustc_path: PathBuf,

    /// The rustdoc executable.
    pub rustdoc_path: Option<PathBuf>,

    /// The Python executable to use for LLDB.
    pub lldb_python: String,

    /// The Python executable to use for htmldocck.
    pub docck_python: String,

    /// The LLVM `FileCheck` binary path.
    pub llvm_filecheck: Option<PathBuf>,

    /// The valgrind path.
    pub valgrind_path: Option<String>,

    /// Whether to fail if we can't run run-pass-valgrind tests under valgrind
    /// (or, alternatively, to silently run them like regular run-pass tests).
    pub force_valgrind: bool,

    /// The path to the Clang executable to run Clang-based tests with. If
    /// `None` then these tests will be ignored.
    pub run_clang_based_tests_with: Option<String>,

    /// The directory containing the tests to run
    pub src_base: PathBuf,

    /// The directory where programs should be built
    pub build_base: PathBuf,

    /// The name of the stage being built (stage1, etc)
    pub stage_id: String,

    /// The test mode, compile-fail, run-fail, run-pass
    pub mode: Mode,

    /// Run ignored tests
    pub run_ignored: bool,

    /// Only run tests that match this filter
    pub filter: Option<String>,

    /// Exactly match the filter, rather than a substring
    pub filter_exact: bool,

    /// Write out a parseable log of tests that were run
    pub logfile: Option<PathBuf>,

    /// A command line to prefix program execution with,
    /// for running under valgrind
    pub runtool: Option<String>,

    /// Flags to pass to the compiler when building for the host
    pub host_rustcflags: Option<String>,

    /// Flags to pass to the compiler when building for the target
    pub target_rustcflags: Option<String>,

    /// Target system to be tested
    pub target: String,

    /// Host triple for the compiler being invoked
    pub host: String,

    /// Path to / name of the GDB executable
    pub gdb: Option<String>,

    /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch
    pub gdb_version: Option<u32>,

    /// Whether GDB has native rust support
    pub gdb_native_rust: bool,

    /// Version of LLDB
    pub lldb_version: Option<String>,

    /// Whether LLDB has native rust support
    pub lldb_native_rust: bool,

    /// Version of LLVM
    pub llvm_version: Option<String>,

    /// Is LLVM a system LLVM
    pub system_llvm: bool,

    /// Path to the android tools
    pub android_cross_path: PathBuf,

    /// Extra parameter to run adb on arm-linux-androideabi
    pub adb_path: String,

    /// Extra parameter to run test suite on arm-linux-androideabi
    pub adb_test_dir: String,

    /// status whether android device available or not
    pub adb_device_status: bool,

    /// the path containing LLDB's Python module
    pub lldb_python_dir: Option<String>,

    /// Explain what's going on
    pub verbose: bool,

    /// Print one character per test instead of one line
    pub quiet: bool,

    /// Whether to use colors in test.
    pub color: ColorConfig,

    /// where to find the remote test client process, if we're using it
    pub remote_test_client: Option<PathBuf>,

    /// mode describing what file the actual ui output will be compared to
    pub compare_mode: Option<CompareMode>,

    /// If true, this will generate a coverage file with UI test files that run `MachineApplicable`
    /// lints but are missing `run-rustfix` annotations. The generated coverage file is created in
    /// `/tmp/rustfix_missing_coverage.txt`
    pub rustfix_coverage: bool,

    // Configuration for various run-make tests frobbing things like C compilers
    // or querying about various LLVM component information.
    pub cc: String,
    pub cxx: String,
    pub cflags: String,
    pub ar: String,
    pub linker: Option<String>,
    pub llvm_components: String,
    pub llvm_cxxflags: String,
    pub nodejs: Option<String>,
}

#[derive(Debug, Clone)]
pub struct TestPaths {
    pub file: PathBuf,         // e.g., compile-test/foo/bar/baz.rs
    pub relative_dir: PathBuf, // e.g., foo/bar
}

/// Used by `ui` tests to generate things like `foo.stderr` from `foo.rs`.
pub fn expected_output_path(
    testpaths: &TestPaths,
    revision: Option<&str>,
    compare_mode: &Option<CompareMode>,
    kind: &str,
) -> PathBuf {
    assert!(UI_EXTENSIONS.contains(&kind));
    let mut parts = Vec::new();

    if let Some(x) = revision {
        parts.push(x);
    }
    if let Some(ref x) = *compare_mode {
        parts.push(x.to_str());
    }
    parts.push(kind);

    let extension = parts.join(".");
    testpaths.file.with_extension(extension)
}

pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT, UI_FIXED];
pub const UI_STDERR: &str = "stderr";
pub const UI_STDOUT: &str = "stdout";
pub const UI_FIXED: &str = "fixed";

/// Absolute path to the directory where all output for all tests in the given
/// `relative_dir` group should reside. Example:
///   /path/to/build/host-triple/test/ui/relative/
/// This is created early when tests are collected to avoid race conditions.
pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf {
    config.build_base.join(relative_dir)
}

/// Generates a unique name for the test, such as `testname.revision.mode`.
pub fn output_testname_unique(
    config: &Config,
    testpaths: &TestPaths,
    revision: Option<&str>,
) -> PathBuf {
    let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str());
    PathBuf::from(&testpaths.file.file_stem().unwrap())
        .with_extra_extension(revision.unwrap_or(""))
        .with_extra_extension(mode)
}

/// Absolute path to the directory where all output for the given
/// test/revision should reside. Example:
///   /path/to/build/host-triple/test/ui/relative/testname.revision.mode/
pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
    output_relative_path(config, &testpaths.relative_dir)
        .join(output_testname_unique(config, testpaths, revision))
}

/// Absolute path to the base filename used as output for the given
/// test/revision. Example:
///   /path/to/build/host-triple/test/ui/relative/testname.revision.mode/testname
pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
    output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap())
}
<commit_msg>s/lints/diagnostics<commit_after>pub use self::Mode::*;

use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use test::ColorConfig;
use crate::util::PathBufExt;

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Mode {
    CompileFail,
    RunFail,
    /// This now behaves like a `ui` test that has an implict `// run-pass`.
    RunPass,
    RunPassValgrind,
    Pretty,
    DebugInfoBoth,
    DebugInfoGdb,
    DebugInfoLldb,
    Codegen,
    Rustdoc,
    CodegenUnits,
    Incremental,
    RunMake,
    Ui,
    JsDocTest,
    MirOpt,
    Assembly,
}

impl Mode {
    pub fn disambiguator(self) -> &'static str {
        // Run-pass and pretty run-pass tests could run concurrently, and if they do,
        // they need to keep their output segregated. Same is true for debuginfo tests that
        // can be run both on gdb and lldb.
        match self {
            Pretty => ".pretty",
            DebugInfoGdb => ".gdb",
            DebugInfoLldb => ".lldb",
            _ => "",
        }
    }
}

impl FromStr for Mode {
    type Err = ();
    fn from_str(s: &str) -> Result<Mode, ()> {
        match s {
            "compile-fail" => Ok(CompileFail),
            "run-fail" => Ok(RunFail),
            "run-pass" => Ok(RunPass),
            "run-pass-valgrind" => Ok(RunPassValgrind),
            "pretty" => Ok(Pretty),
            "debuginfo-both" => Ok(DebugInfoBoth),
            "debuginfo-lldb" => Ok(DebugInfoLldb),
            "debuginfo-gdb" => Ok(DebugInfoGdb),
            "codegen" => Ok(Codegen),
            "rustdoc" => Ok(Rustdoc),
            "codegen-units" => Ok(CodegenUnits),
            "incremental" => Ok(Incremental),
            "run-make" => Ok(RunMake),
            "ui" => Ok(Ui),
            "js-doc-test" => Ok(JsDocTest),
            "mir-opt" => Ok(MirOpt),
            "assembly" => Ok(Assembly),
            _ => Err(()),
        }
    }
}

impl fmt::Display for Mode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match *self {
            CompileFail => "compile-fail",
            RunFail => "run-fail",
            RunPass => "run-pass",
            RunPassValgrind => "run-pass-valgrind",
            Pretty => "pretty",
            DebugInfoBoth => "debuginfo-both",
            DebugInfoGdb => "debuginfo-gdb",
            DebugInfoLldb => "debuginfo-lldb",
            Codegen => "codegen",
            Rustdoc => "rustdoc",
            CodegenUnits => "codegen-units",
            Incremental => "incremental",
            RunMake => "run-make",
            Ui => "ui",
            JsDocTest => "js-doc-test",
            MirOpt => "mir-opt",
            Assembly => "assembly",
        };
        fmt::Display::fmt(s, f)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum CompareMode {
    Nll,
    Polonius,
}

impl CompareMode {
    pub(crate) fn to_str(&self) -> &'static str {
        match *self {
            CompareMode::Nll => "nll",
            CompareMode::Polonius => "polonius",
        }
    }

    pub fn parse(s: String) -> CompareMode {
        match s.as_str() {
            "nll" => CompareMode::Nll,
            "polonius" => CompareMode::Polonius,
            x => panic!("unknown --compare-mode option: {}", x),
        }
    }
}

#[derive(Clone)]
pub struct Config {
    /// `true` to to overwrite stderr/stdout files instead of complaining about changes in output.
    pub bless: bool,

    /// The library paths required for running the compiler.
    pub compile_lib_path: PathBuf,

    /// The library paths required for running compiled programs.
    pub run_lib_path: PathBuf,

    /// The rustc executable.
    pub rustc_path: PathBuf,

    /// The rustdoc executable.
    pub rustdoc_path: Option<PathBuf>,

    /// The Python executable to use for LLDB.
    pub lldb_python: String,

    /// The Python executable to use for htmldocck.
    pub docck_python: String,

    /// The LLVM `FileCheck` binary path.
    pub llvm_filecheck: Option<PathBuf>,

    /// The valgrind path.
    pub valgrind_path: Option<String>,

    /// Whether to fail if we can't run run-pass-valgrind tests under valgrind
    /// (or, alternatively, to silently run them like regular run-pass tests).
    pub force_valgrind: bool,

    /// The path to the Clang executable to run Clang-based tests with. If
    /// `None` then these tests will be ignored.
    pub run_clang_based_tests_with: Option<String>,

    /// The directory containing the tests to run
    pub src_base: PathBuf,

    /// The directory where programs should be built
    pub build_base: PathBuf,

    /// The name of the stage being built (stage1, etc)
    pub stage_id: String,

    /// The test mode, compile-fail, run-fail, run-pass
    pub mode: Mode,

    /// Run ignored tests
    pub run_ignored: bool,

    /// Only run tests that match this filter
    pub filter: Option<String>,

    /// Exactly match the filter, rather than a substring
    pub filter_exact: bool,

    /// Write out a parseable log of tests that were run
    pub logfile: Option<PathBuf>,

    /// A command line to prefix program execution with,
    /// for running under valgrind
    pub runtool: Option<String>,

    /// Flags to pass to the compiler when building for the host
    pub host_rustcflags: Option<String>,

    /// Flags to pass to the compiler when building for the target
    pub target_rustcflags: Option<String>,

    /// Target system to be tested
    pub target: String,

    /// Host triple for the compiler being invoked
    pub host: String,

    /// Path to / name of the GDB executable
    pub gdb: Option<String>,

    /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch
    pub gdb_version: Option<u32>,

    /// Whether GDB has native rust support
    pub gdb_native_rust: bool,

    /// Version of LLDB
    pub lldb_version: Option<String>,

    /// Whether LLDB has native rust support
    pub lldb_native_rust: bool,

    /// Version of LLVM
    pub llvm_version: Option<String>,

    /// Is LLVM a system LLVM
    pub system_llvm: bool,

    /// Path to the android tools
    pub android_cross_path: PathBuf,

    /// Extra parameter to run adb on arm-linux-androideabi
    pub adb_path: String,

    /// Extra parameter to run test suite on arm-linux-androideabi
    pub adb_test_dir: String,

    /// status whether android device available or not
    pub adb_device_status: bool,

    /// the path containing LLDB's Python module
    pub lldb_python_dir: Option<String>,

    /// Explain what's going on
    pub verbose: bool,

    /// Print one character per test instead of one line
    pub quiet: bool,

    /// Whether to use colors in test.
    pub color: ColorConfig,

    /// where to find the remote test client process, if we're using it
    pub remote_test_client: Option<PathBuf>,

    /// mode describing what file the actual ui output will be compared to
    pub compare_mode: Option<CompareMode>,

    /// If true, this will generate a coverage file with UI test files that run `MachineApplicable`
    /// diagnostics but are missing `run-rustfix` annotations. The generated coverage file is
    /// created in `/tmp/rustfix_missing_coverage.txt`
    pub rustfix_coverage: bool,

    // Configuration for various run-make tests frobbing things like C compilers
    // or querying about various LLVM component information.
    pub cc: String,
    pub cxx: String,
    pub cflags: String,
    pub ar: String,
    pub linker: Option<String>,
    pub llvm_components: String,
    pub llvm_cxxflags: String,
    pub nodejs: Option<String>,
}

#[derive(Debug, Clone)]
pub struct TestPaths {
    pub file: PathBuf,         // e.g., compile-test/foo/bar/baz.rs
    pub relative_dir: PathBuf, // e.g., foo/bar
}

/// Used by `ui` tests to generate things like `foo.stderr` from `foo.rs`.
pub fn expected_output_path(
    testpaths: &TestPaths,
    revision: Option<&str>,
    compare_mode: &Option<CompareMode>,
    kind: &str,
) -> PathBuf {
    assert!(UI_EXTENSIONS.contains(&kind));
    let mut parts = Vec::new();

    if let Some(x) = revision {
        parts.push(x);
    }
    if let Some(ref x) = *compare_mode {
        parts.push(x.to_str());
    }
    parts.push(kind);

    let extension = parts.join(".");
    testpaths.file.with_extension(extension)
}

pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT, UI_FIXED];
pub const UI_STDERR: &str = "stderr";
pub const UI_STDOUT: &str = "stdout";
pub const UI_FIXED: &str = "fixed";

/// Absolute path to the directory where all output for all tests in the given
/// `relative_dir` group should reside. Example:
///   /path/to/build/host-triple/test/ui/relative/
/// This is created early when tests are collected to avoid race conditions.
pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf {
    config.build_base.join(relative_dir)
}

/// Generates a unique name for the test, such as `testname.revision.mode`.
pub fn output_testname_unique(
    config: &Config,
    testpaths: &TestPaths,
    revision: Option<&str>,
) -> PathBuf {
    let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str());
    PathBuf::from(&testpaths.file.file_stem().unwrap())
        .with_extra_extension(revision.unwrap_or(""))
        .with_extra_extension(mode)
}

/// Absolute path to the directory where all output for the given
/// test/revision should reside. Example:
///   /path/to/build/host-triple/test/ui/relative/testname.revision.mode/
pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
    output_relative_path(config, &testpaths.relative_dir)
        .join(output_testname_unique(config, testpaths, revision))
}

/// Absolute path to the base filename used as output for the given
/// test/revision. Example:
///   /path/to/build/host-triple/test/ui/relative/testname.revision.mode/testname
pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
    output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap())
}
<|endoftext|>


<commit_before>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load,
                  wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy,
                  wlr_xcursor_manager_get_xcursor, wlr_xcursor_manager_theme};
use types::{Cursor, XCursor, XCursorTheme};
use std::ptr;
use utils::safe_as_cstring;
use std::marker::PhantomData;

#[derive(Debug)]
pub struct XCursorManagerTheme<'manager> {
    theme: *mut wlr_xcursor_manager_theme,
    phantom: PhantomData<XCursorManager<'manager>>
}

#[derive(Debug)]
pub struct XCursorManager<'manager> {
    manager: *mut wlr_xcursor_manager,
    phantom: PhantomData<XCursor<'manager>>
}

impl<'manager> XCursorManagerTheme<'manager> {
    pub(crate) fn new(theme: *mut wlr_xcursor_manager_theme) -> Self {
        XCursorManagerTheme {
            theme: theme,
            phantom: PhantomData
        }
    }

    pub fn scale(&self) -> f32 {
        unsafe {
            (*self.theme).scale
        }
    }

    pub fn theme(self) -> XCursorTheme {
        unsafe {
            XCursorTheme::new((*self.theme).theme)
        }
    }
}

impl<'manager> XCursorManager<'manager> {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager: manager, phantom: PhantomData })
            }
        }
    }

    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    pub fn get_xcursor<T: Into<Option<String>>>(&'manager self, name: T, scale: f32) -> Option<XCursor<'manager>> {
        let name_str = name.into().map(safe_as_cstring);
        let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
        unsafe {
            let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale);
            if xcursor.is_null() {
                None
            } else {
                Some(XCursor::new(xcursor))
            }
        }
    }

    pub fn scaled_themes(&self) -> Vec<XCursorManagerTheme> {
        unsafe {
            let mut result = vec![];

            wl_list_for_each!((*self.manager).scaled_themes, link, (theme: wlr_xcursor_manager_theme) => {
                result.push(XCursorManagerTheme::new(theme))
            });

            result
        }
    }

    /// returns 0 if the scaled theme was successfully loaded and 1 otherwise
    pub fn load(&self, scale: f32) -> i32 {
        unsafe {
            wlr_xcursor_manager_load(self.manager, scale)
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_ptr = safe_as_cstring(name).as_ptr();
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_ptr, cursor.as_ptr());
        }
    }
}

impl<'manager> Drop for XCursorManager<'manager> {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<commit_msg>xcursor manager load return bool<commit_after>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load,
                  wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy,
                  wlr_xcursor_manager_get_xcursor, wlr_xcursor_manager_theme};
use types::{Cursor, XCursor, XCursorTheme};
use std::ptr;
use utils::safe_as_cstring;
use std::marker::PhantomData;

#[derive(Debug)]
pub struct XCursorManagerTheme<'manager> {
    theme: *mut wlr_xcursor_manager_theme,
    phantom: PhantomData<XCursorManager<'manager>>
}

#[derive(Debug)]
pub struct XCursorManager<'manager> {
    manager: *mut wlr_xcursor_manager,
    phantom: PhantomData<XCursor<'manager>>
}

impl<'manager> XCursorManagerTheme<'manager> {
    pub(crate) fn new(theme: *mut wlr_xcursor_manager_theme) -> Self {
        XCursorManagerTheme {
            theme: theme,
            phantom: PhantomData
        }
    }

    pub fn scale(&self) -> f32 {
        unsafe {
            (*self.theme).scale
        }
    }

    pub fn theme(self) -> XCursorTheme {
        unsafe {
            XCursorTheme::new((*self.theme).theme)
        }
    }
}

impl<'manager> XCursorManager<'manager> {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager: manager, phantom: PhantomData })
            }
        }
    }

    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    pub fn get_xcursor<T: Into<Option<String>>>(&'manager self, name: T, scale: f32) -> Option<XCursor<'manager>> {
        let name_str = name.into().map(safe_as_cstring);
        let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
        unsafe {
            let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale);
            if xcursor.is_null() {
                None
            } else {
                Some(XCursor::new(xcursor))
            }
        }
    }

    pub fn scaled_themes(&self) -> Vec<XCursorManagerTheme> {
        unsafe {
            let mut result = vec![];

            wl_list_for_each!((*self.manager).scaled_themes, link, (theme: wlr_xcursor_manager_theme) => {
                result.push(XCursorManagerTheme::new(theme))
            });

            result
        }
    }

    /// returns false if the scaled theme was successfully loaded and true otherwise
    pub fn load(&self, scale: f32) -> bool {
        unsafe {
            match wlr_xcursor_manager_load(self.manager, scale) {
                0 => false,
                _ => true
            }
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_ptr = safe_as_cstring(name).as_ptr();
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_ptr, cursor.as_ptr());
        }
    }
}

impl<'manager> Drop for XCursorManager<'manager> {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<|endoftext|>


<commit_before><commit_msg>Manual serialize/deserialize for ECS<commit_after><|endoftext|>


<commit_before>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::report::Errors;
use crate::syntax::set::OrderedSet as Set;
use crate::syntax::{
    Api, Derive, Enum, ExternFn, ExternType, Impl, Pair, ResolvableName, Struct, Type, TypeAlias,
};
use proc_macro2::Ident;
use quote::ToTokens;
use std::collections::{BTreeMap as Map, HashSet as UnorderedSet};

pub struct Types<'a> {
    pub all: Set<&'a Type>,
    pub structs: Map<&'a Ident, &'a Struct>,
    pub enums: Map<&'a Ident, &'a Enum>,
    pub cxx: Set<&'a Ident>,
    pub rust: Set<&'a Ident>,
    pub aliases: Map<&'a Ident, &'a TypeAlias>,
    pub untrusted: Map<&'a Ident, &'a ExternType>,
    pub required_trivial: Map<&'a Ident, TrivialReason<'a>>,
    pub explicit_impls: Set<&'a Impl>,
    pub resolutions: Map<&'a Ident, &'a Pair>,
}

impl<'a> Types<'a> {
    pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
        let mut all = Set::new();
        let mut structs = Map::new();
        let mut enums = Map::new();
        let mut cxx = Set::new();
        let mut rust = Set::new();
        let mut aliases = Map::new();
        let mut untrusted = Map::new();
        let mut explicit_impls = Set::new();
        let mut resolutions = Map::new();

        fn visit<'a>(all: &mut Set<&'a Type>, ty: &'a Type) {
            all.insert(ty);
            match ty {
                Type::Ident(_) | Type::Str(_) | Type::Void(_) | Type::SliceRefU8(_) => {}
                Type::RustBox(ty)
                | Type::UniquePtr(ty)
                | Type::CxxVector(ty)
                | Type::RustVec(ty) => visit(all, &ty.inner),
                Type::Ref(r) => visit(all, &r.inner),
                Type::Slice(s) => visit(all, &s.inner),
                Type::Fn(f) => {
                    if let Some(ret) = &f.ret {
                        visit(all, ret);
                    }
                    for arg in &f.args {
                        visit(all, &arg.ty);
                    }
                }
            }
        }

        let mut add_resolution = |pair: &'a Pair| {
            resolutions.insert(&pair.rust, pair);
        };

        let mut type_names = UnorderedSet::new();
        let mut function_names = UnorderedSet::new();
        for api in apis {
            // The same identifier is permitted to be declared as both a shared
            // enum and extern C++ type, or shared struct and extern C++ type.
            // That indicates to not emit the C++ enum/struct definition because
            // it's defined by the included headers already.
            //
            // All other cases of duplicate identifiers are reported as an error.
            match api {
                Api::Include(_) => {}
                Api::Struct(strct) => {
                    let ident = &strct.name.rust;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, strct, ident);
                    }
                    structs.insert(&strct.name.rust, strct);
                    for field in &strct.fields {
                        visit(&mut all, &field.ty);
                    }
                    add_resolution(&strct.name);
                }
                Api::Enum(enm) => {
                    let ident = &enm.name.rust;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, enm, ident);
                    }
                    enums.insert(ident, enm);
                    add_resolution(&enm.name);
                }
                Api::CxxType(ety) => {
                    let ident = &ety.name.rust;
                    if !type_names.insert(ident)
                        && (cxx.contains(ident)
                            || !structs.contains_key(ident) && !enums.contains_key(ident))
                    {
                        // If already declared as an extern C++ type, or if
                        // colliding with something which is neither struct nor
                        // enum, then error.
                        duplicate_name(cx, ety, ident);
                    }
                    cxx.insert(ident);
                    if !ety.trusted {
                        untrusted.insert(ident, ety);
                    }
                    add_resolution(&ety.name);
                }
                Api::RustType(ety) => {
                    let ident = &ety.name.rust;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, ety, ident);
                    }
                    rust.insert(ident);
                    add_resolution(&ety.name);
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    // Note: duplication of the C++ name is fine because C++ has
                    // function overloading.
                    if !function_names.insert((&efn.receiver, &efn.name.rust)) {
                        duplicate_name(cx, efn, &efn.name.rust);
                    }
                    for arg in &efn.args {
                        visit(&mut all, &arg.ty);
                    }
                    if let Some(ret) = &efn.ret {
                        visit(&mut all, ret);
                    }
                }
                Api::TypeAlias(alias) => {
                    let ident = &alias.name.rust;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, alias, ident);
                    }
                    cxx.insert(ident);
                    aliases.insert(ident, alias);
                    add_resolution(&alias.name);
                }
                Api::Impl(imp) => {
                    visit(&mut all, &imp.ty);
                    explicit_impls.insert(imp);
                }
            }
        }

        // All these APIs may contain types passed by value. We need to ensure
        // we check that this is permissible. We do this _after_ scanning all
        // the APIs above, in case some function or struct references a type
        // which is declared subsequently.
        let mut required_trivial = Map::new();
        let mut insist_alias_types_are_trivial = |ty: &'a Type, reason| {
            if let Type::Ident(ident) = ty {
                if cxx.contains(&ident.rust) {
                    required_trivial.entry(&ident.rust).or_insert(reason);
                }
            }
        };
        for api in apis {
            match api {
                Api::Struct(strct) => {
                    let reason = TrivialReason::StructField(strct);
                    for field in &strct.fields {
                        insist_alias_types_are_trivial(&field.ty, reason);
                    }
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    let reason = TrivialReason::FunctionArgument(efn);
                    for arg in &efn.args {
                        insist_alias_types_are_trivial(&arg.ty, reason);
                    }
                    if let Some(ret) = &efn.ret {
                        let reason = TrivialReason::FunctionReturn(efn);
                        insist_alias_types_are_trivial(&ret, reason);
                    }
                }
                _ => {}
            }
        }

        Types {
            all,
            structs,
            enums,
            cxx,
            rust,
            aliases,
            untrusted,
            required_trivial,
            explicit_impls,
            resolutions,
        }
    }

    pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
        match ty {
            Type::Ident(ident) => {
                if let Some(strct) = self.structs.get(&ident.rust) {
                    !self.is_pod(strct)
                } else {
                    Atom::from(&ident.rust) == Some(RustString)
                }
            }
            Type::RustVec(_) => true,
            _ => false,
        }
    }

    pub fn is_pod(&self, strct: &Struct) -> bool {
        for derive in &strct.derives {
            if *derive == Derive::Copy {
                return true;
            }
        }
        false
    }

    pub fn resolve(&self, ident: &ResolvableName) -> &Pair {
        self.resolutions
            .get(&ident.rust)
            .expect("Unable to resolve type")
    }
}

impl<'t, 'a> IntoIterator for &'t Types<'a> {
    type Item = &'a Type;
    type IntoIter = crate::syntax::set::Iter<'t, 'a, Type>;
    fn into_iter(self) -> Self::IntoIter {
        self.all.into_iter()
    }
}

#[derive(Copy, Clone)]
pub enum TrivialReason<'a> {
    StructField(&'a Struct),
    FunctionArgument(&'a ExternFn),
    FunctionReturn(&'a ExternFn),
}

fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
    let msg = format!("the name `{}` is defined multiple times", ident);
    cx.error(sp, msg);
}
<commit_msg>Add logic for predicting improper_ctypes lint<commit_after>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::report::Errors;
use crate::syntax::set::OrderedSet as Set;
use crate::syntax::{
    Api, Derive, Enum, ExternFn, ExternType, Impl, Pair, ResolvableName, Struct, Type, TypeAlias,
};
use proc_macro2::Ident;
use quote::ToTokens;
use std::collections::{BTreeMap as Map, HashSet as UnorderedSet};

pub struct Types<'a> {
    pub all: Set<&'a Type>,
    pub structs: Map<&'a Ident, &'a Struct>,
    pub enums: Map<&'a Ident, &'a Enum>,
    pub cxx: Set<&'a Ident>,
    pub rust: Set<&'a Ident>,
    pub aliases: Map<&'a Ident, &'a TypeAlias>,
    pub untrusted: Map<&'a Ident, &'a ExternType>,
    pub required_trivial: Map<&'a Ident, TrivialReason<'a>>,
    pub explicit_impls: Set<&'a Impl>,
    pub resolutions: Map<&'a Ident, &'a Pair>,
}

impl<'a> Types<'a> {
    pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
        let mut all = Set::new();
        let mut structs = Map::new();
        let mut enums = Map::new();
        let mut cxx = Set::new();
        let mut rust = Set::new();
        let mut aliases = Map::new();
        let mut untrusted = Map::new();
        let mut explicit_impls = Set::new();
        let mut resolutions = Map::new();

        fn visit<'a>(all: &mut Set<&'a Type>, ty: &'a Type) {
            all.insert(ty);
            match ty {
                Type::Ident(_) | Type::Str(_) | Type::Void(_) | Type::SliceRefU8(_) => {}
                Type::RustBox(ty)
                | Type::UniquePtr(ty)
                | Type::CxxVector(ty)
                | Type::RustVec(ty) => visit(all, &ty.inner),
                Type::Ref(r) => visit(all, &r.inner),
                Type::Slice(s) => visit(all, &s.inner),
                Type::Fn(f) => {
                    if let Some(ret) = &f.ret {
                        visit(all, ret);
                    }
                    for arg in &f.args {
                        visit(all, &arg.ty);
                    }
                }
            }
        }

        let mut add_resolution = |pair: &'a Pair| {
            resolutions.insert(&pair.rust, pair);
        };

        let mut type_names = UnorderedSet::new();
        let mut function_names = UnorderedSet::new();
        for api in apis {
            // The same identifier is permitted to be declared as both a shared
            // enum and extern C++ type, or shared struct and extern C++ type.
            // That indicates to not emit the C++ enum/struct definition because
            // it's defined by the included headers already.
            //
            // All other cases of duplicate identifiers are reported as an error.
            match api {
                Api::Include(_) => {}
                Api::Struct(strct) => {
                    let ident = &strct.name.rust;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, strct, ident);
                    }
                    structs.insert(&strct.name.rust, strct);
                    for field in &strct.fields {
                        visit(&mut all, &field.ty);
                    }
                    add_resolution(&strct.name);
                }
                Api::Enum(enm) => {
                    let ident = &enm.name.rust;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, enm, ident);
                    }
                    enums.insert(ident, enm);
                    add_resolution(&enm.name);
                }
                Api::CxxType(ety) => {
                    let ident = &ety.name.rust;
                    if !type_names.insert(ident)
                        && (cxx.contains(ident)
                            || !structs.contains_key(ident) && !enums.contains_key(ident))
                    {
                        // If already declared as an extern C++ type, or if
                        // colliding with something which is neither struct nor
                        // enum, then error.
                        duplicate_name(cx, ety, ident);
                    }
                    cxx.insert(ident);
                    if !ety.trusted {
                        untrusted.insert(ident, ety);
                    }
                    add_resolution(&ety.name);
                }
                Api::RustType(ety) => {
                    let ident = &ety.name.rust;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, ety, ident);
                    }
                    rust.insert(ident);
                    add_resolution(&ety.name);
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    // Note: duplication of the C++ name is fine because C++ has
                    // function overloading.
                    if !function_names.insert((&efn.receiver, &efn.name.rust)) {
                        duplicate_name(cx, efn, &efn.name.rust);
                    }
                    for arg in &efn.args {
                        visit(&mut all, &arg.ty);
                    }
                    if let Some(ret) = &efn.ret {
                        visit(&mut all, ret);
                    }
                }
                Api::TypeAlias(alias) => {
                    let ident = &alias.name.rust;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, alias, ident);
                    }
                    cxx.insert(ident);
                    aliases.insert(ident, alias);
                    add_resolution(&alias.name);
                }
                Api::Impl(imp) => {
                    visit(&mut all, &imp.ty);
                    explicit_impls.insert(imp);
                }
            }
        }

        // All these APIs may contain types passed by value. We need to ensure
        // we check that this is permissible. We do this _after_ scanning all
        // the APIs above, in case some function or struct references a type
        // which is declared subsequently.
        let mut required_trivial = Map::new();
        let mut insist_alias_types_are_trivial = |ty: &'a Type, reason| {
            if let Type::Ident(ident) = ty {
                if cxx.contains(&ident.rust) {
                    required_trivial.entry(&ident.rust).or_insert(reason);
                }
            }
        };
        for api in apis {
            match api {
                Api::Struct(strct) => {
                    let reason = TrivialReason::StructField(strct);
                    for field in &strct.fields {
                        insist_alias_types_are_trivial(&field.ty, reason);
                    }
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    let reason = TrivialReason::FunctionArgument(efn);
                    for arg in &efn.args {
                        insist_alias_types_are_trivial(&arg.ty, reason);
                    }
                    if let Some(ret) = &efn.ret {
                        let reason = TrivialReason::FunctionReturn(efn);
                        insist_alias_types_are_trivial(&ret, reason);
                    }
                }
                _ => {}
            }
        }

        Types {
            all,
            structs,
            enums,
            cxx,
            rust,
            aliases,
            untrusted,
            required_trivial,
            explicit_impls,
            resolutions,
        }
    }

    pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
        match ty {
            Type::Ident(ident) => {
                if let Some(strct) = self.structs.get(&ident.rust) {
                    !self.is_pod(strct)
                } else {
                    Atom::from(&ident.rust) == Some(RustString)
                }
            }
            Type::RustVec(_) => true,
            _ => false,
        }
    }

    pub fn is_pod(&self, strct: &Struct) -> bool {
        for derive in &strct.derives {
            if *derive == Derive::Copy {
                return true;
            }
        }
        false
    }

    // Types that trigger rustc's default #[warn(improper_ctypes)] lint, even if
    // they may be otherwise unproblematic to mention in an extern signature.
    // For example in a signature like `extern "C" fn(*const String)`, rustc
    // refuses to believe that C could know how to supply us with a pointer to a
    // Rust String, even though C could easily have obtained that pointer
    // legitimately from a Rust call.
    pub fn is_considered_improper_ctype(&self, ty: &Type) -> bool {
        match ty {
            Type::Ident(ident) => {
                let ident = &ident.rust;
                if let Some(atom) = Atom::from(ident) {
                    atom == RustString
                } else if self.rust.contains(ident) {
                    true
                } else if self.cxx.contains(ident) || self.enums.contains_key(ident) {
                    false
                } else if let Some(strct) = self.structs.get(ident) {
                    for var in &strct.fields {
                        if self.is_considered_improper_ctype(&var.ty) {
                            return true;
                        }
                    }
                    false
                } else {
                    false
                }
            }
            Type::RustBox(_)
            | Type::RustVec(_)
            | Type::Str(_)
            | Type::Fn(_)
            | Type::Void(_)
            | Type::Slice(_)
            | Type::SliceRefU8(_) => true,
            Type::UniquePtr(_) | Type::CxxVector(_) => false,
            Type::Ref(ty) => self.is_considered_improper_ctype(&ty.inner),
        }
    }

    pub fn resolve(&self, ident: &ResolvableName) -> &Pair {
        self.resolutions
            .get(&ident.rust)
            .expect("Unable to resolve type")
    }
}

impl<'t, 'a> IntoIterator for &'t Types<'a> {
    type Item = &'a Type;
    type IntoIter = crate::syntax::set::Iter<'t, 'a, Type>;
    fn into_iter(self) -> Self::IntoIter {
        self.all.into_iter()
    }
}

#[derive(Copy, Clone)]
pub enum TrivialReason<'a> {
    StructField(&'a Struct),
    FunctionArgument(&'a ExternFn),
    FunctionReturn(&'a ExternFn),
}

fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
    let msg = format!("the name `{}` is defined multiple times", ident);
    cx.error(sp, msg);
}
<|endoftext|>


<commit_before>use std::f64::NAN;

use super::js_str::JsStrStruct;
use super::js_var::{JsPtrEnum, JsPtrTag, JsType, JsVar};
use super::js_var::JsType::*;
use super::native_var::NativeVar;

pub trait AsBool {
    fn as_bool(&self) -> bool;
}

impl AsBool for JsVar {
    fn as_bool(&self) -> bool {
        match self.t {
            JsBool(b) => b,
            JsUndef=> false,
            JsNull => false,
            JsNum(n) =>
                if n == 0.0f64 || n == -0.0f64 || n.is_nan() {
                    false
                } else {
                    true
                },
            JsPtr(_) => true, // TODO - this is incorrect
            //JsString(ref s) =>
            //    if s.len() == 0 {
            //        false
            //    } else {
            //        true
            //    },
            //JsSymbol(_) => true,
            //JsObject | JsError(_) | JsFunction(_, _, _) => true,
        }
    }
}

impl AsBool for JsPtrEnum {
    fn as_bool(&self) -> bool {
        match *self {
            JsPtrEnum::JsSym(_) |
            JsPtrEnum::JsFn(_) |
            JsPtrEnum::JsObj(_) |
            JsPtrEnum::NativeFn(_) => true,
            JsPtrEnum::JsStr(ref s) => s.text.len() != 0,
            JsPtrEnum::NativeVar(ref nv) => nv.ptr.as_ref().map(|ptr| ptr.as_bool()).unwrap_or(nv.var.as_bool()),
        }
    }
}

pub trait AsNumber {
    fn as_number(&self) -> f64;
}

impl AsNumber for JsVar {
    fn as_number(&self) -> f64 {
        match self.t {
            JsBool(b) => if b { 1f64 } else { 0f64 },
            JsUndef => NAN,
            JsNull => 0f64,
            JsNum(n) => n,
            JsPtr(_) => NAN,
        }
    }
}

impl AsNumber for JsPtrEnum {
    fn as_number(&self) -> f64 {
        match self {
            // TODO: Change this to throw a TypeError
            &JsPtrEnum::JsSym(_) => panic!("Cannot convert a Symbol to a number."),
            &JsPtrEnum::JsStr(JsStrStruct { ref text }) => {
                if text.len() == 0 {
                    return 0.0
                }

                text.parse().unwrap_or(NAN)
            }
            &JsPtrEnum::NativeVar(NativeVar { ref var, ref ptr, .. }) => match (var, ptr) {
                (_, &Some(ref ptr)) => ptr.as_number(),
                (ref var, &None) => var.as_number(),
            },
            _ => NAN
        }
    }
}

pub trait AsString {
    fn as_string(&self) -> String;
}

impl AsString for JsType {
    fn as_string(&self) -> String {
        let s = match *self {
            JsBool(true) => "true",
            JsBool(false) => "false",
            JsUndef => "undefined",
            JsNull => "null",
            JsNum(n) => return format!("{}", n),

            // NOTE: These cases should never actually be used; in the case that the variable is
            // a JsPtr, the corresponding JsPtrEnum's string coercion should be used.
            JsPtr(JsPtrTag::JsSym) => "Symbol(...)",
            JsPtr(JsPtrTag::JsStr) => "\"...\"",
            JsPtr(JsPtrTag::JsObj) => "{ ... }",
            JsPtr(JsPtrTag::JsFn{..}) => "function() { ... }",
            JsPtr(JsPtrTag::NativeFn{..}) => "function() { [native code] }",
            JsPtr(JsPtrTag::NativeVar{..}) => "[native code]",
        };

        String::from(s)
    }
}

impl AsString for JsPtrEnum {
    fn as_string(&self) -> String {
        match *self {
            JsPtrEnum::JsSym(ref s) => format!("Symbol({})", s),
            JsPtrEnum::JsStr(ref s) => s.text.to_owned(),

            // TODO: Check object's `toString` method
            JsPtrEnum::JsObj(_) => String::from("[object Object]"),

            // TODO: A function's string representation is apparently the string of source code that
            // created it; the AST doesn't currently support this, so we'll need to do some
            // restructuring before we can support this.
            JsPtrEnum::JsFn(_) => String::from("[function]"),
            JsPtrEnum::NativeFn(_) => String::from("[native function]"),
            JsPtrEnum::NativeVar(NativeVar { ref var, ref ptr, ..}) => ptr.as_ref().map(|p| p.as_string()).unwrap_or(var.t.as_string()),
        }
    }
}
<commit_msg>fix string to number coercion<commit_after>use std::f64::NAN;

use super::js_str::JsStrStruct;
use super::js_var::{JsPtrEnum, JsPtrTag, JsType, JsVar};
use super::js_var::JsType::*;
use super::native_var::NativeVar;

pub trait AsBool {
    fn as_bool(&self) -> bool;
}

impl AsBool for JsVar {
    fn as_bool(&self) -> bool {
        match self.t {
            JsBool(b) => b,
            JsUndef=> false,
            JsNull => false,
            JsNum(n) =>
                if n == 0.0f64 || n == -0.0f64 || n.is_nan() {
                    false
                } else {
                    true
                },
            JsPtr(_) => true, // TODO - this is incorrect
            //JsString(ref s) =>
            //    if s.len() == 0 {
            //        false
            //    } else {
            //        true
            //    },
            //JsSymbol(_) => true,
            //JsObject | JsError(_) | JsFunction(_, _, _) => true,
        }
    }
}

impl AsBool for JsPtrEnum {
    fn as_bool(&self) -> bool {
        match *self {
            JsPtrEnum::JsSym(_) |
            JsPtrEnum::JsFn(_) |
            JsPtrEnum::JsObj(_) |
            JsPtrEnum::NativeFn(_) => true,
            JsPtrEnum::JsStr(ref s) => s.text.len() != 0,
            JsPtrEnum::NativeVar(ref nv) => nv.ptr.as_ref().map(|ptr| ptr.as_bool()).unwrap_or(nv.var.as_bool()),
        }
    }
}

pub trait AsNumber {
    fn as_number(&self) -> f64;
}

impl AsNumber for JsVar {
    fn as_number(&self) -> f64 {
        match self.t {
            JsBool(b) => if b { 1f64 } else { 0f64 },
            JsUndef => NAN,
            JsNull => 0f64,
            JsNum(n) => n,
            JsPtr(_) => NAN,
        }
    }
}

impl AsNumber for JsPtrEnum {
    fn as_number(&self) -> f64 {
        match self {
            // TODO: Change this to throw a TypeError
            &JsPtrEnum::JsSym(_) => panic!("Cannot convert a Symbol to a number."),
            &JsPtrEnum::JsStr(JsStrStruct { ref text }) => {
                if text.len() == 0 {
                    return 0.0
                }

                text.trim().parse().unwrap_or(NAN)
            }
            &JsPtrEnum::NativeVar(NativeVar { ref var, ref ptr, .. }) => match (var, ptr) {
                (_, &Some(ref ptr)) => ptr.as_number(),
                (ref var, &None) => var.as_number(),
            },
            _ => NAN
        }
    }
}

pub trait AsString {
    fn as_string(&self) -> String;
}

impl AsString for JsType {
    fn as_string(&self) -> String {
        let s = match *self {
            JsBool(true) => "true",
            JsBool(false) => "false",
            JsUndef => "undefined",
            JsNull => "null",
            JsNum(n) => return format!("{}", n),

            // NOTE: These cases should never actually be used; in the case that the variable is
            // a JsPtr, the corresponding JsPtrEnum's string coercion should be used.
            JsPtr(JsPtrTag::JsSym) => "Symbol(...)",
            JsPtr(JsPtrTag::JsStr) => "\"...\"",
            JsPtr(JsPtrTag::JsObj) => "{ ... }",
            JsPtr(JsPtrTag::JsFn{..}) => "function() { ... }",
            JsPtr(JsPtrTag::NativeFn{..}) => "function() { [native code] }",
            JsPtr(JsPtrTag::NativeVar{..}) => "[native code]",
        };

        String::from(s)
    }
}

impl AsString for JsPtrEnum {
    fn as_string(&self) -> String {
        match *self {
            JsPtrEnum::JsSym(ref s) => format!("Symbol({})", s),
            JsPtrEnum::JsStr(ref s) => s.text.to_owned(),

            // TODO: Check object's `toString` method
            JsPtrEnum::JsObj(_) => String::from("[object Object]"),

            // TODO: A function's string representation is apparently the string of source code that
            // created it; the AST doesn't currently support this, so we'll need to do some
            // restructuring before we can support this.
            JsPtrEnum::JsFn(_) => String::from("[function]"),
            JsPtrEnum::NativeFn(_) => String::from("[native function]"),
            JsPtrEnum::NativeVar(NativeVar { ref var, ref ptr, ..}) => ptr.as_ref().map(|p| p.as_string()).unwrap_or(var.t.as_string()),
        }
    }
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    gcc::compile_library(
        "libstb_truetype.a", &["stb_truetype.c"]);
}
<commit_msg>build.rs: Updated for cargo 66849de 2015-03-10<commit_after>extern crate gcc;

fn main() {
    let out_dir = std::env::var("OUT_DIR").unwrap();
    gcc::compile_library(
        "libstb_truetype.a", &["stb_truetype.c"]);
    println!("cargo:rustc-flags=-L native={}", out_dir);
}
<|endoftext|>


<commit_before>//! This build script ensures that clippy is not compiled with an
//! incompatible version of rust. It will panic with a descriptive
//! error message instead.
//!
//! We specifially want to ensure that clippy is only built with a
//! rustc version that is newer or equal to the one specified in the
//! `min_version.txt` file.
//!
//! `min_version.txt` is in the repo but also in the `.gitignore` to
//! make sure that it is not updated manually by accident. Only CI
//! should update that file.
//!
//! This build script was originally taken from the Rocket web framework:
//! https://github.com/SergioBenitez/Rocket

extern crate rustc_version;
extern crate ansi_term;

use std::env;
use rustc_version::{version_meta, version_meta_for, Channel, Version, VersionMeta};
use ansi_term::Colour::Red;

fn main() {
    let string = include_str!("min_version.txt");
    let min_version_meta = version_meta_for(string)
        .expect("Could not parse version string in min_version.txt");
    let current_version_meta = version_meta()
        .expect("Could not retrieve current rustc version information from ENV");

    let min_version = min_version_meta.clone().semver;
    let min_date_str = min_version_meta.clone().commit_date
        .expect("min_version.txt does not contain a rustc commit date");

    let current_version = current_version_meta.clone().semver;
    let current_date_str = current_version_meta.clone().commit_date
        .expect("current rustc version information does not contain a rustc commit date");

    let print_version_err = |version: &Version, date: &str| {
        eprintln!("> {} {}. {} {}.\n",
                  "Installed rustc version is:",
                  format!("{} ({})", version, date),
                  "Minimum required rustc version:",
                  format!("{} ({})", min_version, min_date_str));
    };

    if !correct_channel(&current_version_meta) {
        eprintln!("\n{} {}",
                  Red.bold().paint("error:"),
                  "clippy requires a nightly version of Rust.");
        print_version_err(&current_version, &*current_date_str);
        eprintln!("{}{}{}",
                  "See the README (",
                  "https://github.com/rust-lang-nursery/rust-clippy#usage",
                  ") for more information.");
        panic!("Aborting compilation due to incompatible compiler.")
    }

    let current_date = str_to_ymd(&current_date_str).unwrap();
    let min_date = str_to_ymd(&min_date_str).unwrap();

    if current_date < min_date {
        eprintln!("\n{} {}",
                  Red.bold().paint("error:"),
                  "clippy does not support this version of rustc nightly.");
        eprintln!("> {}{}{}",
                  "Use `",
                  "rustup update",
                  "` or your preferred method to update Rust.");
        print_version_err(&current_version, &*current_date_str);
        panic!("Aborting compilation due to incompatible compiler.")
    }

    // Forward the profile to the main compilation
    println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
    // Don't rebuild even if nothing changed
    println!("cargo:rerun-if-changed=build.rs");
}

fn correct_channel(version_meta: &VersionMeta) -> bool {
    match version_meta.channel {
        Channel::Stable | Channel::Beta => {
            false
        },
        Channel::Nightly | Channel::Dev => {
            true
        }
    }
}

/// Convert a string of %Y-%m-%d to a single u32 maintaining ordering.
fn str_to_ymd(ymd: &str) -> Option<u32> {
    let ymd: Vec<u32> = ymd.split("-").filter_map(|s| s.parse::<u32>().ok()).collect();
    if ymd.len() != 3 {
        return None
    }

    let (y, m, d) = (ymd[0], ymd[1], ymd[2]);
    Some((y << 9) | (m << 5) | d)
}
<commit_msg>Fix build script for dev channel<commit_after>//! This build script ensures that clippy is not compiled with an
//! incompatible version of rust. It will panic with a descriptive
//! error message instead.
//!
//! We specifially want to ensure that clippy is only built with a
//! rustc version that is newer or equal to the one specified in the
//! `min_version.txt` file.
//!
//! `min_version.txt` is in the repo but also in the `.gitignore` to
//! make sure that it is not updated manually by accident. Only CI
//! should update that file.
//!
//! This build script was originally taken from the Rocket web framework:
//! https://github.com/SergioBenitez/Rocket

extern crate rustc_version;
extern crate ansi_term;

use std::env;
use rustc_version::{version_meta, version_meta_for, Channel, Version, VersionMeta};
use ansi_term::Colour::Red;

fn main() {
    check_rustc_version();

    // Forward the profile to the main compilation
    println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
    // Don't rebuild even if nothing changed
    println!("cargo:rerun-if-changed=build.rs");
}

fn check_rustc_version() {
    let string = include_str!("min_version.txt");
    let min_version_meta = version_meta_for(string)
        .expect("Could not parse version string in min_version.txt");
    let current_version_meta = version_meta()
        .expect("Could not retrieve current rustc version information from ENV");

    let min_version = min_version_meta.clone().semver;
    let min_date_str = min_version_meta.clone().commit_date
        .expect("min_version.txt does not contain a rustc commit date");

    // Dev channel (rustc built from git) does not have any date or commit information in rustc -vV
    // `current_version_meta.commit_date` would crash, so we return early here.
    if current_version_meta.channel == Channel::Dev {
        return
    }

    let current_version = current_version_meta.clone().semver;
    let current_date_str = current_version_meta.clone().commit_date
        .expect("current rustc version information does not contain a rustc commit date");

    let print_version_err = |version: &Version, date: &str| {
        eprintln!("> {} {}. {} {}.\n",
                  "Installed rustc version is:",
                  format!("{} ({})", version, date),
                  "Minimum required rustc version:",
                  format!("{} ({})", min_version, min_date_str));
    };

    if !correct_channel(&current_version_meta) {
        eprintln!("\n{} {}",
                  Red.bold().paint("error:"),
                  "clippy requires a nightly version of Rust.");
        print_version_err(&current_version, &*current_date_str);
        eprintln!("{}{}{}",
                  "See the README (",
                  "https://github.com/rust-lang-nursery/rust-clippy#usage",
                  ") for more information.");
        panic!("Aborting compilation due to incompatible compiler.")
    }

    let current_date = str_to_ymd(&current_date_str).unwrap();
    let min_date = str_to_ymd(&min_date_str).unwrap();

    if current_date < min_date {
        eprintln!("\n{} {}",
                  Red.bold().paint("error:"),
                  "clippy does not support this version of rustc nightly.");
        eprintln!("> {}{}{}",
                  "Use `",
                  "rustup update",
                  "` or your preferred method to update Rust.");
        print_version_err(&current_version, &*current_date_str);
        panic!("Aborting compilation due to incompatible compiler.")
    }
}

fn correct_channel(version_meta: &VersionMeta) -> bool {
    match version_meta.channel {
        Channel::Stable | Channel::Beta => {
            false
        },
        Channel::Nightly | Channel::Dev => {
            true
        }
    }
}

/// Convert a string of %Y-%m-%d to a single u32 maintaining ordering.
fn str_to_ymd(ymd: &str) -> Option<u32> {
    let ymd: Vec<u32> = ymd.split("-").filter_map(|s| s.parse::<u32>().ok()).collect();
    if ymd.len() != 3 {
        return None
    }

    let (y, m, d) = (ymd[0], ymd[1], ymd[2]);
    Some((y << 9) | (m << 5) | d)
}
<|endoftext|>


<commit_before>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Finds the required `libclang` libraries and links to them.
//!
//! # Environment Variables
//!
//! This build script can make use of several environment variables to help it find the required
//! static or dynamic libraries.
//!
//! * LLVM_CONFIG_PATH - provides a path to an `llvm-config` executable
//! * LIBCLANG_PATH - provides a path to a directory containing a `libclang` shared library
//! * LIBCLANG_STATIC_PATH - provides a path to a directory containing LLVM and Clang static libraries

#![allow(unused_attributes)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]

extern crate glob;

use std::env;
use std::fs::{self, File};
use std::io::{Read};
use std::path::{Path, PathBuf};
use std::process::{Command};

use glob::{MatchOptions};

/// Returns a path to one of the supplied files if such a file can be found in the supplied directory.
fn contains<D: AsRef<Path>>(directory: D, files: &[String]) -> Option<PathBuf> {
    files.iter().map(|file| directory.as_ref().join(file)).find(|file| file.exists())
}

/// Runs a console command, returning the output if the command was successfully executed.
fn run(command: &str, arguments: &[&str]) -> Option<String> {
    Command::new(command).args(arguments).output().map(|o| {
        String::from_utf8_lossy(&o.stdout).into_owned()
    }).ok()
}

/// Runs `llvm-config`, returning the output if the command was successfully executed.
fn run_llvm_config(arguments: &[&str]) -> Result<String, String> {
    match run(&env::var("LLVM_CONFIG_PATH").unwrap_or_else(|_| "llvm-config".into()), arguments) {
        Some(output) => Ok(output),
        None => {
            let message = format!(
                "couldn't execute `llvm-config {}`, set the LLVM_CONFIG_PATH environment variable \
                to a path to a valid `llvm-config` executable",
                arguments.join(" "),
            );
            Err(message)
        },
    }
}

/// Backup search directory globs for FreeBSD and Linux.
const SEARCH_LINUX: &'static [&'static str] = &[
    "/usr/lib*",
    "/usr/lib*/*",
    "/usr/lib*/*/*",
    "/usr/local/lib*",
    "/usr/local/lib*/*",
    "/usr/local/lib*/*/*",
    "/usr/local/llvm*/lib",
];

/// Backup search directory globs for OS X.
const SEARCH_OSX: &'static [&'static str] = &[
    "/usr/local/opt/llvm*/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/usr/local/opt/llvm*/lib/llvm*/lib",
];

/// Backup search directory globs for Windows.
const SEARCH_WINDOWS: &'static [&'static str] = &[
    "C:\\LLVM\\lib",
    "C:\\Program Files*\\LLVM\\lib",
    "C:\\MSYS*\\MinGW*\\lib",
];

/// Indicates the type of library being searched for.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Library {
    Dynamic,
    Static,
}

impl Library {
    /// Checks whether the supplied file is a valid library for the architecture.
    fn check(&self, file: &PathBuf) -> Result<(), String> {
        if cfg!(any(target_os="freebsd", target_os="linux")) {
            if *self == Library::Static {
                return Ok(());
            }
            let mut file = try!(File::open(file).map_err(|e| e.to_string()));
            let mut elf = [0; 5];
            try!(file.read_exact(&mut elf).map_err(|e| e.to_string()));
            if elf[..4] != [127, 69, 76, 70] {
                return Err("invalid ELF header".into());
            }
            if cfg!(target_pointer_width="32") && elf[4] != 1 {
                return Err("invalid ELF class (64-bit)".into());
            }
            if cfg!(target_pointer_width="64") && elf[4] != 2 {
                return Err("invalid ELF class (32-bit)".into());
            }
            Ok(())
        } else {
            Ok(())
        }
    }
}

/// Searches for a library, returning the directory it can be found in if the search was successful.
fn find(library: Library, files: &[String], env: &str) -> Result<PathBuf, String> {
    let mut skipped = vec![];

    /// Attempts to return the supplied file.
    macro_rules! try_file {
        ($file:expr) => ({
            match library.check(&$file) {
                Ok(_) => return Ok($file),
                Err(message) => skipped.push(format!("({}: {})", $file.display(), message)),
            }
        });
    }

    /// Searches the supplied directory and, on Windows, any relevant sibling directories.
    macro_rules! search_directory {
        ($directory:ident) => {
            if let Some(file) = contains(&$directory, files) {
                try_file!(file);
            }

            // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory while
            // `libclang.lib` is usually found in the LLVM `lib` directory. To keep things
            // consistent with other platforms, only LLVM `lib` directories are included in the
            // backup search directory globs so we need to search the LLVM `bin` directory here.
            if cfg!(target_os="windows") && $directory.ends_with("lib") {
                let sibling = $directory.parent().unwrap().join("bin");
                if let Some(file) = contains(&sibling, files) {
                    try_file!(file);
                }
            }
        }
    }

    // Search the directory provided by the relevant environment variable if it is set.
    if let Ok(directory) = env::var(env).map(|d| Path::new(&d).to_path_buf()) {
        search_directory!(directory);
    }

    // Search the `bin` and `lib` subdirectories in the directory returned by
    // `llvm-config --prefix` if `llvm-config` is available.
    if let Ok(output) = run_llvm_config(&["--prefix"]) {
        let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
        let bin = directory.join("bin");
        if let Some(file) = contains(&bin, files) {
            try_file!(file);
        }
        let lib = directory.join("lib");
        if let Some(file) = contains(&lib, files) {
            try_file!(file);
        }
    }

    // Search the backup directories.
    let search = if cfg!(any(target_os="freebsd", target_os="linux")) {
        SEARCH_LINUX
    } else if cfg!(target_os="macos") {
        SEARCH_OSX
    } else if cfg!(target_os="windows") {
        SEARCH_WINDOWS
    } else {
        &[]
    };
    for pattern in search {
        let mut options = MatchOptions::new();
        options.case_sensitive = false;
        options.require_literal_separator = true;
        if let Ok(paths) = glob::glob_with(pattern, &options) {
            for path in paths.filter_map(Result::ok).filter(|p| p.is_dir()) {
                search_directory!(path);
            }
        }
    }

    let message = format!(
        "couldn't find any of [{}], set the {} environment variable to a path where one of these \
         files can be found (skipped: [{}])",
        files.iter().map(|f| format!("'{}'", f)).collect::<Vec<_>>().join(", "),
        env,
        skipped.join(", "),
    );
    Err(message)
}

/// Searches for a `libclang` shared library, returning the path to such a shared library if the
/// search was successful.
pub fn find_shared_library() -> Result<PathBuf, String> {
    let mut files = vec![format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)];
    if cfg!(target_os="linux") {
        // Some Linux distributions don't create a `libclang.so` symlink.
        //
        // FIXME: We should improve our detection and selection of versioned libraries.
        files.push("libclang.so.1".into());
    }
    if cfg!(target_os="windows") {
        // The official LLVM build uses `libclang.dll` on Windows instead of `clang.dll`. However,
        // unofficial builds such as MinGW use `clang.dll`.
        files.push("libclang.dll".into());
    }
    find(Library::Dynamic, &files, "LIBCLANG_PATH")
}

/// Returns the name of an LLVM or Clang library from a path to such a library.
fn get_library_name(path: &Path) -> Option<String> {
    path.file_stem().map(|l| l.to_string_lossy()[3..].into())
}

/// Returns the LLVM libraries required to link to `libclang` statically.
fn get_llvm_libraries() -> Vec<String> {
    run_llvm_config(&["--libs"]).unwrap().split_whitespace().filter_map(|p| {
        // Depending on the version of `llvm-config` in use, listed libraries may be in one of two
        // forms, a full path to the library or simply prefixed with `-l`.
        if p.starts_with("-l") {
            Some(p[2..].into())
        } else {
            get_library_name(Path::new(p))
        }
    }).collect()
}

/// Clang libraries required to link to `libclang` 3.5 and later statically.
const CLANG_LIBRARIES: &'static [&'static str] = &[
    "clang",
    "clangAST",
    "clangAnalysis",
    "clangBasic",
    "clangDriver",
    "clangEdit",
    "clangFrontend",
    "clangIndex",
    "clangLex",
    "clangParse",
    "clangRewrite",
    "clangSema",
    "clangSerialization",
];

/// Returns the Clang libraries required to link to `libclang` statically.
fn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> {
    let pattern = directory.as_ref().join("libclang*.a").to_string_lossy().to_string();
    if let Ok(libraries) = glob::glob(&pattern) {
        libraries.filter_map(|l| l.ok().and_then(|l| get_library_name(&l))).collect()
    } else {
        CLANG_LIBRARIES.iter().map(|l| l.to_string()).collect()
    }
}

/// Find and link to `libclang` statically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_static() {
    let file = find(Library::Static, &["libclang.a".into()], "LIBCLANG_STATIC_PATH").unwrap();
    let directory = file.parent().unwrap();
    print!("cargo:rustc-flags=");

    // Specify required Clang static libraries.
    print!("-L {} ", directory.display());
    for library in get_clang_libraries(directory) {
        print!("-l static={} ", library);
    }

    // Specify required LLVM static libraries.
    print!("-L {} ", run_llvm_config(&["--libdir"]).unwrap().trim_right());
    for library in get_llvm_libraries() {
        print!("-l static={} ", library);
    }

    // Specify required system libraries.
    if cfg!(target_os="freebsd") {
        println!("-l ffi -l ncursesw -l c++ -l z");
    } else if cfg!(target_os="linux") {
        println!("-l ffi -l ncursesw -l stdc++ -l z");
    } else if cfg!(target_os="macos") {
        println!("-l ffi -l ncurses -l c++ -l z");
    } else {
        panic!("unsupported operating system for static linking");
    }
}

/// Find and link to `libclang` dynamically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_dynamic() {
    let file = find_shared_library().unwrap();
    let directory = file.parent().unwrap();
    println!("cargo:rustc-link-search={}", directory.display());

    if cfg!(all(target_os="windows", target_env="msvc")) {
        // Find the `libclang` stub static library required for the MSVC toolchain.
        let libdir = if !directory.ends_with("bin") {
            directory.to_owned()
        } else {
            directory.parent().unwrap().join("lib")
        };
        if libdir.join("libclang.lib").exists() {
            println!("cargo:rustc-link-search={}", libdir.display());
        } else if libdir.join("libclang.dll.a").exists() {
            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`. It is linkable with
            // the MSVC linker, but Rust doesn't recognize the `.a` suffix, so we need to copy it
            // with a different name.
            //
            // FIXME: Maybe we can just hardlink or symlink it?
            let out = env::var("OUT_DIR").unwrap();
            fs::copy(libdir.join("libclang.dll.a"), Path::new(&out).join("libclang.lib")).unwrap();
            println!("cargo:rustc-link-search=native={}", out);
        } else {
            panic!(
                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be available in {}",
                file.display(),
                libdir.display(),
            );
        }
        println!("cargo:rustc-link-lib=dylib=libclang");
    } else {
        println!("cargo:rustc-link-lib=dylib=clang");
    }
}

#[cfg_attr(feature="runtime", allow(dead_code))]
fn main() {
    if cfg!(feature="runtime") {
        if cfg!(feature="static") {
            panic!("`runtime` and `static` features can't be combined");
        }
    } else if cfg!(feature="static") {
        link_static();
    } else {
        link_dynamic();
    }
}
<commit_msg>Fix clippy warnings<commit_after>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Finds the required `libclang` libraries and links to them.
//!
//! # Environment Variables
//!
//! This build script can make use of several environment variables to help it find the required
//! static or dynamic libraries.
//!
//! * `LLVM_CONFIG_PATH` - provides a path to an `llvm-config` executable
//! * `LIBCLANG_PATH` - provides a path to a directory containing a `libclang` shared library
//! * `LIBCLANG_STATIC_PATH` - provides a path to a directory containing LLVM and Clang static libraries

#![allow(unused_attributes)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]

extern crate glob;

use std::env;
use std::fs::{self, File};
use std::io::{Read};
use std::path::{Path, PathBuf};
use std::process::{Command};

use glob::{MatchOptions};

/// Returns a path to one of the supplied files if such a file can be found in the supplied directory.
fn contains<D: AsRef<Path>>(directory: D, files: &[String]) -> Option<PathBuf> {
    files.iter().map(|file| directory.as_ref().join(file)).find(|file| file.exists())
}

/// Runs a console command, returning the output if the command was successfully executed.
fn run(command: &str, arguments: &[&str]) -> Option<String> {
    Command::new(command).args(arguments).output().map(|o| {
        String::from_utf8_lossy(&o.stdout).into_owned()
    }).ok()
}

/// Runs `llvm-config`, returning the output if the command was successfully executed.
fn run_llvm_config(arguments: &[&str]) -> Result<String, String> {
    match run(&env::var("LLVM_CONFIG_PATH").unwrap_or_else(|_| "llvm-config".into()), arguments) {
        Some(output) => Ok(output),
        None => {
            let message = format!(
                "couldn't execute `llvm-config {}`, set the LLVM_CONFIG_PATH environment variable \
                to a path to a valid `llvm-config` executable",
                arguments.join(" "),
            );
            Err(message)
        },
    }
}

/// Backup search directory globs for FreeBSD and Linux.
const SEARCH_LINUX: &'static [&'static str] = &[
    "/usr/lib*",
    "/usr/lib*/*",
    "/usr/lib*/*/*",
    "/usr/local/lib*",
    "/usr/local/lib*/*",
    "/usr/local/lib*/*/*",
    "/usr/local/llvm*/lib",
];

/// Backup search directory globs for OS X.
const SEARCH_OSX: &'static [&'static str] = &[
    "/usr/local/opt/llvm*/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/usr/local/opt/llvm*/lib/llvm*/lib",
];

/// Backup search directory globs for Windows.
const SEARCH_WINDOWS: &'static [&'static str] = &[
    "C:\\LLVM\\lib",
    "C:\\Program Files*\\LLVM\\lib",
    "C:\\MSYS*\\MinGW*\\lib",
];

/// Indicates the type of library being searched for.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Library {
    Dynamic,
    Static,
}

impl Library {
    /// Checks whether the supplied file is a valid library for the architecture.
    fn check(&self, file: &PathBuf) -> Result<(), String> {
        if cfg!(any(target_os="freebsd", target_os="linux")) {
            if *self == Library::Static {
                return Ok(());
            }
            let mut file = try!(File::open(file).map_err(|e| e.to_string()));
            let mut elf = [0; 5];
            try!(file.read_exact(&mut elf).map_err(|e| e.to_string()));
            if elf[..4] != [127, 69, 76, 70] {
                return Err("invalid ELF header".into());
            }
            if cfg!(target_pointer_width="32") && elf[4] != 1 {
                return Err("invalid ELF class (64-bit)".into());
            }
            if cfg!(target_pointer_width="64") && elf[4] != 2 {
                return Err("invalid ELF class (32-bit)".into());
            }
            Ok(())
        } else {
            Ok(())
        }
    }
}

/// Searches for a library, returning the directory it can be found in if the search was successful.
fn find(library: Library, files: &[String], env: &str) -> Result<PathBuf, String> {
    let mut skipped = vec![];

    /// Attempts to return the supplied file.
    macro_rules! try_file {
        ($file:expr) => ({
            match library.check(&$file) {
                Ok(_) => return Ok($file),
                Err(message) => skipped.push(format!("({}: {})", $file.display(), message)),
            }
        });
    }

    /// Searches the supplied directory and, on Windows, any relevant sibling directories.
    macro_rules! search_directory {
        ($directory:ident) => {
            if let Some(file) = contains(&$directory, files) {
                try_file!(file);
            }

            // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory while
            // `libclang.lib` is usually found in the LLVM `lib` directory. To keep things
            // consistent with other platforms, only LLVM `lib` directories are included in the
            // backup search directory globs so we need to search the LLVM `bin` directory here.
            if cfg!(target_os="windows") && $directory.ends_with("lib") {
                let sibling = $directory.parent().unwrap().join("bin");
                if let Some(file) = contains(&sibling, files) {
                    try_file!(file);
                }
            }
        }
    }

    // Search the directory provided by the relevant environment variable if it is set.
    if let Ok(directory) = env::var(env).map(|d| Path::new(&d).to_path_buf()) {
        search_directory!(directory);
    }

    // Search the `bin` and `lib` subdirectories in the directory returned by
    // `llvm-config --prefix` if `llvm-config` is available.
    if let Ok(output) = run_llvm_config(&["--prefix"]) {
        let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
        let bin = directory.join("bin");
        if let Some(file) = contains(&bin, files) {
            try_file!(file);
        }
        let lib = directory.join("lib");
        if let Some(file) = contains(&lib, files) {
            try_file!(file);
        }
    }

    // Search the backup directories.
    let search = if cfg!(any(target_os="freebsd", target_os="linux")) {
        SEARCH_LINUX
    } else if cfg!(target_os="macos") {
        SEARCH_OSX
    } else if cfg!(target_os="windows") {
        SEARCH_WINDOWS
    } else {
        &[]
    };
    for pattern in search {
        let mut options = MatchOptions::new();
        options.case_sensitive = false;
        options.require_literal_separator = true;
        if let Ok(paths) = glob::glob_with(pattern, &options) {
            for path in paths.filter_map(Result::ok).filter(|p| p.is_dir()) {
                search_directory!(path);
            }
        }
    }

    let message = format!(
        "couldn't find any of [{}], set the {} environment variable to a path where one of these \
         files can be found (skipped: [{}])",
        files.iter().map(|f| format!("'{}'", f)).collect::<Vec<_>>().join(", "),
        env,
        skipped.join(", "),
    );
    Err(message)
}

/// Searches for a `libclang` shared library, returning the path to such a shared library if the
/// search was successful.
pub fn find_shared_library() -> Result<PathBuf, String> {
    let mut files = vec![format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)];
    if cfg!(target_os="linux") {
        // Some Linux distributions don't create a `libclang.so` symlink.
        //
        // FIXME: We should improve our detection and selection of versioned libraries.
        files.push("libclang.so.1".into());
    }
    if cfg!(target_os="windows") {
        // The official LLVM build uses `libclang.dll` on Windows instead of `clang.dll`. However,
        // unofficial builds such as MinGW use `clang.dll`.
        files.push("libclang.dll".into());
    }
    find(Library::Dynamic, &files, "LIBCLANG_PATH")
}

/// Returns the name of an LLVM or Clang library from a path to such a library.
fn get_library_name(path: &Path) -> Option<String> {
    path.file_stem().map(|l| l.to_string_lossy()[3..].into())
}

/// Returns the LLVM libraries required to link to `libclang` statically.
fn get_llvm_libraries() -> Vec<String> {
    run_llvm_config(&["--libs"]).unwrap().split_whitespace().filter_map(|p| {
        // Depending on the version of `llvm-config` in use, listed libraries may be in one of two
        // forms, a full path to the library or simply prefixed with `-l`.
        if p.starts_with("-l") {
            Some(p[2..].into())
        } else {
            get_library_name(Path::new(p))
        }
    }).collect()
}

/// Clang libraries required to link to `libclang` 3.5 and later statically.
const CLANG_LIBRARIES: &'static [&'static str] = &[
    "clang",
    "clangAST",
    "clangAnalysis",
    "clangBasic",
    "clangDriver",
    "clangEdit",
    "clangFrontend",
    "clangIndex",
    "clangLex",
    "clangParse",
    "clangRewrite",
    "clangSema",
    "clangSerialization",
];

/// Returns the Clang libraries required to link to `libclang` statically.
fn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> {
    let pattern = directory.as_ref().join("libclang*.a").to_string_lossy().to_string();
    if let Ok(libraries) = glob::glob(&pattern) {
        libraries.filter_map(|l| l.ok().and_then(|l| get_library_name(&l))).collect()
    } else {
        CLANG_LIBRARIES.iter().map(|l| l.to_string()).collect()
    }
}

/// Find and link to `libclang` statically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_static() {
    let file = find(Library::Static, &["libclang.a".into()], "LIBCLANG_STATIC_PATH").unwrap();
    let directory = file.parent().unwrap();
    print!("cargo:rustc-flags=");

    // Specify required Clang static libraries.
    print!("-L {} ", directory.display());
    for library in get_clang_libraries(directory) {
        print!("-l static={} ", library);
    }

    // Specify required LLVM static libraries.
    print!("-L {} ", run_llvm_config(&["--libdir"]).unwrap().trim_right());
    for library in get_llvm_libraries() {
        print!("-l static={} ", library);
    }

    // Specify required system libraries.
    if cfg!(target_os="freebsd") {
        println!("-l ffi -l ncursesw -l c++ -l z");
    } else if cfg!(target_os="linux") {
        println!("-l ffi -l ncursesw -l stdc++ -l z");
    } else if cfg!(target_os="macos") {
        println!("-l ffi -l ncurses -l c++ -l z");
    } else {
        panic!("unsupported operating system for static linking");
    }
}

/// Find and link to `libclang` dynamically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_dynamic() {
    let file = find_shared_library().unwrap();
    let directory = file.parent().unwrap();
    println!("cargo:rustc-link-search={}", directory.display());

    if cfg!(all(target_os="windows", target_env="msvc")) {
        // Find the `libclang` stub static library required for the MSVC toolchain.
        let libdir = if !directory.ends_with("bin") {
            directory.to_owned()
        } else {
            directory.parent().unwrap().join("lib")
        };
        if libdir.join("libclang.lib").exists() {
            println!("cargo:rustc-link-search={}", libdir.display());
        } else if libdir.join("libclang.dll.a").exists() {
            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`. It is linkable with
            // the MSVC linker, but Rust doesn't recognize the `.a` suffix, so we need to copy it
            // with a different name.
            //
            // FIXME: Maybe we can just hardlink or symlink it?
            let out = env::var("OUT_DIR").unwrap();
            fs::copy(libdir.join("libclang.dll.a"), Path::new(&out).join("libclang.lib")).unwrap();
            println!("cargo:rustc-link-search=native={}", out);
        } else {
            panic!(
                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be available in {}",
                file.display(),
                libdir.display(),
            );
        }
        println!("cargo:rustc-link-lib=dylib=libclang");
    } else {
        println!("cargo:rustc-link-lib=dylib=clang");
    }
}

#[cfg_attr(feature="runtime", allow(dead_code))]
fn main() {
    if cfg!(feature="runtime") {
        if cfg!(feature="static") {
            panic!("`runtime` and `static` features can't be combined");
        }
    } else if cfg!(feature="static") {
        link_static();
    } else {
        link_dynamic();
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Write;
use std::process::{Command, Output};
use std::path;
use std::env;

fn run_cmd(name: &str, command: &mut Command) -> Output {
    let res = command.output();
    match res {
        Ok(output) => if !output.status.success() {
            panic!("{} failed:\n{}", name, String::from_utf8_lossy(&output.stderr[..]))
        } else {
            output
        },
        Err(err) =>
            panic!("{} failed:\n{}", name, err)
    }
}

fn main()
{
    let dir_var = match env::var("OUT_DIR") {
        Ok(dir) => dir,
        Err(e) => panic!("Could not get env value OUT_DIR: {}", e)
    };

    let compile_flags = env::var("LIBYAML_CFLAGS").unwrap_or("".to_string());

    let out_file = path::Path::new(&dir_var).join("codegen");
    let mut gcc_cmd = Command::new("gcc");
    gcc_cmd.arg("src/codegen/type_size.c")
        .arg(&compile_flags)
        .arg("-o").arg(&out_file);

    run_cmd("gcc", &mut gcc_cmd);

    let mut codegen_cmd = Command::new(&out_file);
    let output = run_cmd("codegen", &mut codegen_cmd);

    let mut f = match File::create("src/type_size.rs") {
        Ok(f) => f,
        Err(e) => panic!("Could not open file src/type_size.rs: {}", e)
    };

    match f.write_all(&output.stdout[..]) {
        Err(e) => panic!("Could not write to src/type_size.rs: {}", e),
        Ok(_) => ()
    }
}
<commit_msg>More through error message for build script<commit_after>#![feature(path_ext)]

use std::fs::{File, PathExt};
use std::io::{stderr, Write};
use std::process::{Command, Output};
use std::path::Path;
use std::env;

fn run_cmd(command: &mut Command) -> Output {
    let stream = stderr();
    let mut f = stream.lock();
    let res = command.output();
    match res {
        Ok(output) => if !output.status.success() {
            write!(&mut f, "Command `{:?}` failed", command).unwrap();
            panic!("{}", String::from_utf8_lossy(&output.stderr[..]))
        } else {
            output
        },
        Err(err) => {
            write!(&mut f, "Command `{:?}` failed", command).unwrap();
            panic!("{}", err)
        }
    }
}

fn main()
{
    let source_file = Path::new("src/codegen/type_size.c");
    if !source_file.exists() {
        panic!("Could not find file: {}", source_file.to_string_lossy());
    }

    let out_dir_var = match env::var("OUT_DIR") {
        Ok(dir) => dir,
        Err(e) => panic!("Could not get env value OUT_DIR: {}", e)
    };
    let out_dir = Path::new(&out_dir_var);
    if !out_dir.exists() {
        panic!("Could not find directory: {}", out_dir.to_string_lossy());
    }

    let out_file = out_dir.join("codegen");

    let mut gcc_cmd = Command::new("gcc");
    gcc_cmd.arg(source_file)
        .arg("-o").arg(&out_file);

    match env::var("LIBYAML_CFLAGS") {
        Ok(compile_flags) => { gcc_cmd.arg(&compile_flags); },
        Err(_) => ()
    }

    run_cmd(&mut gcc_cmd);

    let mut codegen_cmd = Command::new(&out_file);
    let output = run_cmd(&mut codegen_cmd);

    let mut f = match File::create("src/type_size.rs") {
        Ok(f) => f,
        Err(e) => panic!("Could not open file src/type_size.rs: {}", e)
    };

    match f.write_all(&output.stdout[..]) {
        Err(e) => panic!("Could not write to src/type_size.rs: {}", e),
        Ok(_) => ()
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::Path;
use std::process::Command;

fn main() {
    cc::Build::new()
        .file("src/cxx.cc")
        .cpp(true)
        .cpp_link_stdlib(None) // linked via link-cplusplus crate
        .flag_if_supported(cxxbridge_flags::STD)
        .compile("cxxbridge05");

    println!("cargo:rerun-if-changed=src/cxx.cc");
    println!("cargo:rerun-if-changed=include/cxx.h");
    println!("cargo:rustc-cfg=built_with_cargo");

    if let Some(manifest_dir) = env::var_os("CARGO_MANIFEST_DIR") {
        let cxx_h = Path::new(&manifest_dir).join("include").join("cxx.h");
        println!("cargo:HEADER={}", cxx_h.to_string_lossy());
    }

    if let Some(rustc) = rustc_version() {
        if rustc.minor < 43 {
            println!("cargo:warning=The cxx crate requires a rustc version 1.43.0 or newer.");
            println!(
                "cargo:warning=You appear to be building with: {}",
                rustc.version,
            );
        }
    }
}

struct RustVersion {
    version: String,
    minor: u32,
}

fn rustc_version() -> Option<RustVersion> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = String::from_utf8(output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    let minor = pieces.next()?.parse().ok()?;
    Some(RustVersion { version, minor })
}
<commit_msg>Raise rustc checked in build script to 1.48<commit_after>use std::env;
use std::path::Path;
use std::process::Command;

fn main() {
    cc::Build::new()
        .file("src/cxx.cc")
        .cpp(true)
        .cpp_link_stdlib(None) // linked via link-cplusplus crate
        .flag_if_supported(cxxbridge_flags::STD)
        .compile("cxxbridge05");

    println!("cargo:rerun-if-changed=src/cxx.cc");
    println!("cargo:rerun-if-changed=include/cxx.h");
    println!("cargo:rustc-cfg=built_with_cargo");

    if let Some(manifest_dir) = env::var_os("CARGO_MANIFEST_DIR") {
        let cxx_h = Path::new(&manifest_dir).join("include").join("cxx.h");
        println!("cargo:HEADER={}", cxx_h.to_string_lossy());
    }

    if let Some(rustc) = rustc_version() {
        if rustc.minor < 48 {
            println!("cargo:warning=The cxx crate requires a rustc version 1.48.0 or newer.");
            println!(
                "cargo:warning=You appear to be building with: {}",
                rustc.version,
            );
        }
    }
}

struct RustVersion {
    version: String,
    minor: u32,
}

fn rustc_version() -> Option<RustVersion> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = String::from_utf8(output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    let minor = pieces.next()?.parse().ok()?;
    Some(RustVersion { version, minor })
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    gcc::compile_library("libpredicates.a", &["src/predicates.c"]);
}
<commit_msg>Always optimize.<commit_after>extern crate gcc;

use std::env;

fn main() {
    gcc::Config::new()
                .file("src/predicates.c")
				.opt_level(2)
                .compile("libpredicates.a");
}
<|endoftext|>