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

#![deny(warnings)]

extern crate filetime;

use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::{fs, env};

use filetime::FileTime;

/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
///
/// This is currently used judiciously throughout the build system rather than
/// using a `Result` with `try!`, but this may change one day...
#[macro_export]
macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum BuildExpectation {
    Succeeding,
    Failing,
    None,
}

pub fn run(cmd: &mut Command, expect: BuildExpectation) {
    println!("running: {:?}", cmd);
    run_silent(cmd, expect);
}

pub fn run_silent(cmd: &mut Command, expect: BuildExpectation) {
    if !try_run_silent(cmd, expect) {
        std::process::exit(1);
    }
}

pub fn try_run_silent(cmd: &mut Command, expect: BuildExpectation) -> bool {
    let status = match cmd.status() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    process_status(
        cmd,
        status.success(),
        expect,
        || println!("\n\ncommand did not execute successfully: {:?}\n\
                    expected success, got: {}\n\n",
                    cmd,
                    status))
}

fn process_status<F: FnOnce()>(
    cmd: &Command,
    success: bool,
    expect: BuildExpectation,
    f: F,
) -> bool {
    use BuildExpectation::*;
    match (expect, success) {
        (None, false) => { f(); false },
        // Non-tool build succeeds, everything is good
        (None, true) => true,
        // Tool expected to work and is working
        (Succeeding, true) => true,
        // Tool expected to fail and is failing
        (Failing, false) => {
            println!("This failure is expected (see `src/tools/toolstate.toml`)");
            true
        },
        // Tool expected to work, but is failing
        (Succeeding, false) => {
            f();
            println!("You can disable the tool in `src/tools/toolstate.toml`");
            false
        },
        // Tool expected to fail, but is working
        (Failing, true) => {
            println!("Expected `{:?}` to fail, but it succeeded.\n\
                     Please adjust `src/tools/toolstate.toml` accordingly", cmd);
            false
        }
    }
}

pub fn run_suppressed(cmd: &mut Command, expect: BuildExpectation) {
    if !try_run_suppressed(cmd, expect) {
        std::process::exit(1);
    }
}

pub fn try_run_suppressed(cmd: &mut Command, expect: BuildExpectation) -> bool {
    let output = match cmd.output() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    process_status(
        cmd,
        output.status.success(),
        expect,
        || println!("\n\ncommand did not execute successfully: {:?}\n\
                  expected success, got: {}\n\n\
                  stdout ----\n{}\n\
                  stderr ----\n{}\n\n",
                 cmd,
                 output.status,
                 String::from_utf8_lossy(&output.stdout),
                 String::from_utf8_lossy(&output.stderr)))
}

pub fn gnu_target(target: &str) -> String {
    match target {
        "i686-pc-windows-msvc" => "i686-pc-win32".to_string(),
        "x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(),
        "i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(),
        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(),
        s => s.to_string(),
    }
}

pub fn make(host: &str) -> PathBuf {
    if host.contains("bitrig") || host.contains("dragonfly") ||
        host.contains("freebsd") || host.contains("netbsd") ||
        host.contains("openbsd") {
        PathBuf::from("gmake")
    } else {
        PathBuf::from("make")
    }
}

pub fn output(cmd: &mut Command) -> String {
    let output = match cmd.stderr(Stdio::inherit()).output() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    if !output.status.success() {
        panic!("command did not execute successfully: {:?}\n\
                expected success, got: {}",
               cmd,
               output.status);
    }
    String::from_utf8(output.stdout).unwrap()
}

pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
    let mut stack = dir.read_dir().unwrap()
                       .map(|e| e.unwrap())
                       .filter(|e| &*e.file_name() != ".git")
                       .collect::<Vec<_>>();
    while let Some(entry) = stack.pop() {
        let path = entry.path();
        if entry.file_type().unwrap().is_dir() {
            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
        } else {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }
}

/// Returns the last-modified time for `path`, or zero if it doesn't exist.
pub fn mtime(path: &Path) -> FileTime {
    fs::metadata(path).map(|f| {
        FileTime::from_last_modification_time(&f)
    }).unwrap_or(FileTime::zero())
}

/// Returns whether `dst` is up to date given that the file or files in `src`
/// are used to generate it.
///
/// Uses last-modified time checks to verify this.
pub fn up_to_date(src: &Path, dst: &Path) -> bool {
    let threshold = mtime(dst);
    let meta = match fs::metadata(src) {
        Ok(meta) => meta,
        Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
    };
    if meta.is_dir() {
        dir_up_to_date(src, &threshold)
    } else {
        FileTime::from_last_modification_time(&meta) <= threshold
    }
}

#[must_use]
pub struct NativeLibBoilerplate {
    pub src_dir: PathBuf,
    pub out_dir: PathBuf,
}

impl Drop for NativeLibBoilerplate {
    fn drop(&mut self) {
        t!(File::create(self.out_dir.join("rustbuild.timestamp")));
    }
}

// Perform standard preparations for native libraries that are build only once for all stages.
// Emit rerun-if-changed and linking attributes for Cargo, check if any source files are
// updated, calculate paths used later in actual build with CMake/make or C/C++ compiler.
// If Err is returned, then everything is up-to-date and further build actions can be skipped.
// Timestamps are created automatically when the result of `native_lib_boilerplate` goes out
// of scope, so all the build actions should be completed until then.
pub fn native_lib_boilerplate(src_name: &str,
                              out_name: &str,
                              link_name: &str,
                              search_subdir: &str)
                              -> Result<NativeLibBoilerplate, ()> {
    let current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let src_dir = current_dir.join("..").join(src_name);
    rerun_if_changed_anything_in_dir(&src_dir);

    let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap());
    let out_dir = PathBuf::from(out_dir).join(out_name);
    t!(fs::create_dir_all(&out_dir));
    if link_name.contains('=') {
        println!("cargo:rustc-link-lib={}", link_name);
    } else {
        println!("cargo:rustc-link-lib=static={}", link_name);
    }
    println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display());

    let timestamp = out_dir.join("rustbuild.timestamp");
    if !up_to_date(Path::new("build.rs"), &timestamp) || !up_to_date(&src_dir, &timestamp) {
        Ok(NativeLibBoilerplate { src_dir: src_dir, out_dir: out_dir })
    } else {
        Err(())
    }
}

pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoilerplate, ()> {
    let (link_name, search_path) = match &*env::var("TARGET").unwrap() {
        "x86_64-unknown-linux-gnu" => (
            format!("clang_rt.{}-x86_64", sanitizer_name),
            "build/lib/linux",
        ),
        "x86_64-apple-darwin" => (
            format!("dylib=clang_rt.{}_osx_dynamic", sanitizer_name),
            "build/lib/darwin",
        ),
        _ => return Err(()),
    };
    native_lib_boilerplate("libcompiler_builtins/compiler-rt",
                           sanitizer_name,
                           &link_name,
                           search_path)
}

fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool {
    t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
        let meta = t!(e.metadata());
        if meta.is_dir() {
            dir_up_to_date(&e.path(), threshold)
        } else {
            FileTime::from_last_modification_time(&meta) < *threshold
        }
    })
}

fn fail(s: &str) -> ! {
    println!("\n\n{}\n\n", s);
    std::process::exit(1);
}
<commit_msg>Rollup merge of #46421 - mnd:fix-build-for-guix, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(warnings)]

extern crate filetime;

use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::{fs, env};

use filetime::FileTime;

/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
///
/// This is currently used judiciously throughout the build system rather than
/// using a `Result` with `try!`, but this may change one day...
#[macro_export]
macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum BuildExpectation {
    Succeeding,
    Failing,
    None,
}

pub fn run(cmd: &mut Command, expect: BuildExpectation) {
    println!("running: {:?}", cmd);
    run_silent(cmd, expect);
}

pub fn run_silent(cmd: &mut Command, expect: BuildExpectation) {
    if !try_run_silent(cmd, expect) {
        std::process::exit(1);
    }
}

pub fn try_run_silent(cmd: &mut Command, expect: BuildExpectation) -> bool {
    let status = match cmd.status() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    process_status(
        cmd,
        status.success(),
        expect,
        || println!("\n\ncommand did not execute successfully: {:?}\n\
                    expected success, got: {}\n\n",
                    cmd,
                    status))
}

fn process_status<F: FnOnce()>(
    cmd: &Command,
    success: bool,
    expect: BuildExpectation,
    f: F,
) -> bool {
    use BuildExpectation::*;
    match (expect, success) {
        (None, false) => { f(); false },
        // Non-tool build succeeds, everything is good
        (None, true) => true,
        // Tool expected to work and is working
        (Succeeding, true) => true,
        // Tool expected to fail and is failing
        (Failing, false) => {
            println!("This failure is expected (see `src/tools/toolstate.toml`)");
            true
        },
        // Tool expected to work, but is failing
        (Succeeding, false) => {
            f();
            println!("You can disable the tool in `src/tools/toolstate.toml`");
            false
        },
        // Tool expected to fail, but is working
        (Failing, true) => {
            println!("Expected `{:?}` to fail, but it succeeded.\n\
                     Please adjust `src/tools/toolstate.toml` accordingly", cmd);
            false
        }
    }
}

pub fn run_suppressed(cmd: &mut Command, expect: BuildExpectation) {
    if !try_run_suppressed(cmd, expect) {
        std::process::exit(1);
    }
}

pub fn try_run_suppressed(cmd: &mut Command, expect: BuildExpectation) -> bool {
    let output = match cmd.output() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    process_status(
        cmd,
        output.status.success(),
        expect,
        || println!("\n\ncommand did not execute successfully: {:?}\n\
                  expected success, got: {}\n\n\
                  stdout ----\n{}\n\
                  stderr ----\n{}\n\n",
                 cmd,
                 output.status,
                 String::from_utf8_lossy(&output.stdout),
                 String::from_utf8_lossy(&output.stderr)))
}

pub fn gnu_target(target: &str) -> String {
    match target {
        "i686-pc-windows-msvc" => "i686-pc-win32".to_string(),
        "x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(),
        "i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(),
        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(),
        s => s.to_string(),
    }
}

pub fn make(host: &str) -> PathBuf {
    if host.contains("bitrig") || host.contains("dragonfly") ||
        host.contains("freebsd") || host.contains("netbsd") ||
        host.contains("openbsd") {
        PathBuf::from("gmake")
    } else {
        PathBuf::from("make")
    }
}

pub fn output(cmd: &mut Command) -> String {
    let output = match cmd.stderr(Stdio::inherit()).output() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    if !output.status.success() {
        panic!("command did not execute successfully: {:?}\n\
                expected success, got: {}",
               cmd,
               output.status);
    }
    String::from_utf8(output.stdout).unwrap()
}

pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
    let mut stack = dir.read_dir().unwrap()
                       .map(|e| e.unwrap())
                       .filter(|e| &*e.file_name() != ".git")
                       .collect::<Vec<_>>();
    while let Some(entry) = stack.pop() {
        let path = entry.path();
        if entry.file_type().unwrap().is_dir() {
            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
        } else {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }
}

/// Returns the last-modified time for `path`, or zero if it doesn't exist.
pub fn mtime(path: &Path) -> FileTime {
    fs::metadata(path).map(|f| {
        FileTime::from_last_modification_time(&f)
    }).unwrap_or(FileTime::zero())
}

/// Returns whether `dst` is up to date given that the file or files in `src`
/// are used to generate it.
///
/// Uses last-modified time checks to verify this.
pub fn up_to_date(src: &Path, dst: &Path) -> bool {
    if !dst.exists() {
        return false;
    }
    let threshold = mtime(dst);
    let meta = match fs::metadata(src) {
        Ok(meta) => meta,
        Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
    };
    if meta.is_dir() {
        dir_up_to_date(src, &threshold)
    } else {
        FileTime::from_last_modification_time(&meta) <= threshold
    }
}

#[must_use]
pub struct NativeLibBoilerplate {
    pub src_dir: PathBuf,
    pub out_dir: PathBuf,
}

impl Drop for NativeLibBoilerplate {
    fn drop(&mut self) {
        t!(File::create(self.out_dir.join("rustbuild.timestamp")));
    }
}

// Perform standard preparations for native libraries that are build only once for all stages.
// Emit rerun-if-changed and linking attributes for Cargo, check if any source files are
// updated, calculate paths used later in actual build with CMake/make or C/C++ compiler.
// If Err is returned, then everything is up-to-date and further build actions can be skipped.
// Timestamps are created automatically when the result of `native_lib_boilerplate` goes out
// of scope, so all the build actions should be completed until then.
pub fn native_lib_boilerplate(src_name: &str,
                              out_name: &str,
                              link_name: &str,
                              search_subdir: &str)
                              -> Result<NativeLibBoilerplate, ()> {
    let current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let src_dir = current_dir.join("..").join(src_name);
    rerun_if_changed_anything_in_dir(&src_dir);

    let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap());
    let out_dir = PathBuf::from(out_dir).join(out_name);
    t!(fs::create_dir_all(&out_dir));
    if link_name.contains('=') {
        println!("cargo:rustc-link-lib={}", link_name);
    } else {
        println!("cargo:rustc-link-lib=static={}", link_name);
    }
    println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display());

    let timestamp = out_dir.join("rustbuild.timestamp");
    if !up_to_date(Path::new("build.rs"), &timestamp) || !up_to_date(&src_dir, &timestamp) {
        Ok(NativeLibBoilerplate { src_dir: src_dir, out_dir: out_dir })
    } else {
        Err(())
    }
}

pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoilerplate, ()> {
    let (link_name, search_path) = match &*env::var("TARGET").unwrap() {
        "x86_64-unknown-linux-gnu" => (
            format!("clang_rt.{}-x86_64", sanitizer_name),
            "build/lib/linux",
        ),
        "x86_64-apple-darwin" => (
            format!("dylib=clang_rt.{}_osx_dynamic", sanitizer_name),
            "build/lib/darwin",
        ),
        _ => return Err(()),
    };
    native_lib_boilerplate("libcompiler_builtins/compiler-rt",
                           sanitizer_name,
                           &link_name,
                           search_path)
}

fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool {
    t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
        let meta = t!(e.metadata());
        if meta.is_dir() {
            dir_up_to_date(&e.path(), threshold)
        } else {
            FileTime::from_last_modification_time(&meta) < *threshold
        }
    })
}

fn fail(s: &str) -> ! {
    println!("\n\n{}\n\n", s);
    std::process::exit(1);
}
<|endoftext|>


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

use syntax::ast;
use llvm::LLVMRustHasFeature;
use rustc::session::Session;
use rustc_trans::back::write::create_target_machine;
use syntax::feature_gate::UnstableFeatures;
use syntax::symbol::Symbol;
use libc::c_char;

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

const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];

const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                 "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                 "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                 "sse4a\0", "rdrnd\0", "rdseed\0"];

/// Add `target_feature = "..."` cfgs for a variety of platform
/// specific features (SSE, NEON etc.).
///
/// This is performed by checking whether a whitelisted set of
/// features is available on the target machine, by querying LLVM.
pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
    let target_machine = create_target_machine(sess);

    let whitelist = match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        _ => &[],
    };

    let tf = Symbol::intern("target_feature");
    for feat in whitelist {
        assert_eq!(feat.chars().last(), Some('\0'));
        if unsafe { LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } {
            cfg.insert((tf, Some(Symbol::intern(&feat[..feat.len() - 1]))));
        }
    }

    let requested_features = sess.opts.cg.target_feature.split(',');
    let unstable_options = sess.opts.debugging_opts.unstable_options;
    let is_nightly = UnstableFeatures::from_environment().is_nightly_build();
    let found_negative = requested_features.clone().any(|r| r == "-crt-static");
    let found_positive = requested_features.clone().any(|r| r == "+crt-static");

    // If the target we're compiling for requests a static crt by default,
    // then see if the `-crt-static` feature was passed to disable that.
    // Otherwise if we don't have a static crt by default then see if the
    // `+crt-static` feature was passed.
    let crt_static = if sess.target.target.options.crt_static_default {
        !found_negative
    } else {
        found_positive
    };

    // If we switched from the default then that's only allowed on nightly, so
    // gate that here.
    if (found_positive || found_negative) && (!is_nightly || !unstable_options) {
        sess.fatal("specifying the `crt-static` target feature is only allowed \
                    on the nightly channel with `-Z unstable-options` passed \
                    as well");
    }

    if crt_static {
        cfg.insert((tf, Some(Symbol::intern("crt-static"))));
    }
}
<commit_msg>Rollup merge of #40431 - fsasm:master, r=BurntSushi<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::ast;
use llvm::LLVMRustHasFeature;
use rustc::session::Session;
use rustc_trans::back::write::create_target_machine;
use syntax::feature_gate::UnstableFeatures;
use syntax::symbol::Symbol;
use libc::c_char;

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

const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];

const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                 "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                 "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                 "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0"];

/// Add `target_feature = "..."` cfgs for a variety of platform
/// specific features (SSE, NEON etc.).
///
/// This is performed by checking whether a whitelisted set of
/// features is available on the target machine, by querying LLVM.
pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
    let target_machine = create_target_machine(sess);

    let whitelist = match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        _ => &[],
    };

    let tf = Symbol::intern("target_feature");
    for feat in whitelist {
        assert_eq!(feat.chars().last(), Some('\0'));
        if unsafe { LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } {
            cfg.insert((tf, Some(Symbol::intern(&feat[..feat.len() - 1]))));
        }
    }

    let requested_features = sess.opts.cg.target_feature.split(',');
    let unstable_options = sess.opts.debugging_opts.unstable_options;
    let is_nightly = UnstableFeatures::from_environment().is_nightly_build();
    let found_negative = requested_features.clone().any(|r| r == "-crt-static");
    let found_positive = requested_features.clone().any(|r| r == "+crt-static");

    // If the target we're compiling for requests a static crt by default,
    // then see if the `-crt-static` feature was passed to disable that.
    // Otherwise if we don't have a static crt by default then see if the
    // `+crt-static` feature was passed.
    let crt_static = if sess.target.target.options.crt_static_default {
        !found_negative
    } else {
        found_positive
    };

    // If we switched from the default then that's only allowed on nightly, so
    // gate that here.
    if (found_positive || found_negative) && (!is_nightly || !unstable_options) {
        sess.fatal("specifying the `crt-static` target feature is only allowed \
                    on the nightly channel with `-Z unstable-options` passed \
                    as well");
    }

    if crt_static {
        cfg.insert((tf, Some(Symbol::intern("crt-static"))));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
use std::str::FromStr;

use nom::{self, AsChar};

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct MakeRule {
    pub targets: Vec<String>,
    pub prereqs: Vec<String>,
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct MakeFile(Vec<MakeRule>);

impl FromStr for MakeFile {
    type Err = nom::Err<nom::error::ErrorKind>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match make_rules(s) {
            Ok((_, rules)) => Ok(MakeFile(rules)),
            Err(err) => Err(match err {
                nom::Err::Incomplete(n) => nom::Err::Incomplete(n),
                nom::Err::Error(e) => nom::Err::Error(e.1),
                nom::Err::Failure(e) => nom::Err::Failure(e.1),
            }),
        }
    }
}

impl MakeFile {
    pub fn rules(&self) -> &Vec<MakeRule> {
        &self.0
    }
}

fn is_file_name<C: AsChar>(chr: C) -> bool {
    let chr = chr.as_char();
    !(chr == '\\'
        || chr == ':'
        || chr == '\r'
        || chr == '\n'
        || chr == ' '
        || chr == '\0')
}

fn is_space<C: AsChar>(chr: C) -> bool {
    let chr = chr.as_char();
    chr == ' ' || chr == '\t'
}

fn is_rule_separator<C: AsChar>(chr: C) -> bool {
    let chr = chr.as_char();
    chr == '\n' || chr == '\r' || is_space(chr)
}

named!(pub filename<&str, String>,
    escaped_transform!(
        take_while1!(is_file_name),
        '\\',
        alt!(
            tag!("\\") => { |_| "\\" }
            | tag!(" ") => { |_| " " }
            | tag!("r") => { |_| "\r" }
            | tag!("n") => { |_| "\n" }
            | tag!("t") => { |_| "\t" }
            | nom::character::complete::line_ending => { |_| "" }
        )
    )
);

named!(make_targets<&str, Vec<String>>,
    separated_list!(
        escaped!(
            take_while1!(is_space),
            '\\',
            nom::character::complete::line_ending
        ),
        filename
    )
);

named!(make_rule<&str, MakeRule>,
    do_parse!(
        targets: make_targets >>
        take_while!(is_space) >>
        tag!(":") >>
        take_while!(is_space) >>
        prereqs: make_targets >>
        (MakeRule { targets, prereqs })
    )
);

named!(make_rules<&str, Vec<MakeRule>>,
    ws!(separated_list!(
        take_while!(is_rule_separator),
        make_rule
    ))
);

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

    #[test]
    fn it_works() {
        assert_eq!(
            filename("\\nfoo\\\\bar\\t\\ baz.o\0"),
            Ok(("\0", String::from("\nfoo\\bar\t baz.o")))
        );

        assert_eq!(
            filename("foo\\\nbar.o\0"),
            Ok(("\0", String::from("foobar.o")))
        );

        assert_eq!(
            filename("foo\\\r\nbar.o\0"),
            Ok(("\0", String::from("foobar.o")))
        );

        assert_eq!(
            make_targets("foo\\ ooo.o bar.o      baz.o:"),
            Ok((
                ":",
                vec!["foo ooo.o".into(), "bar.o".into(), "baz.o".into()]
            ))
        );

        assert_eq!(
            make_rule("foo.o bar.o   :  foo.c \\\n \\\r\n bar.c \n"),
            Ok((
                " \n",
                MakeRule {
                    targets: vec!["foo.o".into(), "bar.o".into()],
                    prereqs: vec!["foo.c".into(), "bar.c".into()],
                }
            ))
        );

        let makefile =
            "foo.o: foo.c foo.h  \t\n  \n\r\n bar.o: bar.c foo.h\n\0";

        assert_eq!(
            make_rules(makefile),
            Ok((
                "\0",
                vec![
                    MakeRule {
                        targets: vec!["foo.o".into()],
                        prereqs: vec!["foo.c".into(), "foo.h".into()],
                    },
                    MakeRule {
                        targets: vec!["bar.o".into()],
                        prereqs: vec!["bar.c".into(), "foo.h".into()],
                    }
                ]
            ))
        );

        assert_eq!(
            make_rules("obj/bar.o: src/bar.c src/foo.h\r\n\0"),
            Ok((
                "\0",
                vec![MakeRule {
                    targets: vec!["obj/bar.o".into()],
                    prereqs: vec!["src/bar.c".into(), "src/foo.h".into()],
                },]
            ))
        );
    }
}
<commit_msg>Fix deprecation warning<commit_after>// Copyright (c) 2018 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
use std::str::FromStr;

use nom::{self, AsChar};

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct MakeRule {
    pub targets: Vec<String>,
    pub prereqs: Vec<String>,
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct MakeFile(Vec<MakeRule>);

impl FromStr for MakeFile {
    type Err = nom::Err<nom::error::ErrorKind>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match make_rules(s) {
            Ok((_, rules)) => Ok(MakeFile(rules)),
            Err(err) => Err(match err {
                nom::Err::Incomplete(n) => nom::Err::Incomplete(n),
                nom::Err::Error(e) => nom::Err::Error(e.1),
                nom::Err::Failure(e) => nom::Err::Failure(e.1),
            }),
        }
    }
}

impl MakeFile {
    pub fn rules(&self) -> &Vec<MakeRule> {
        &self.0
    }
}

fn is_file_name<C: AsChar>(chr: C) -> bool {
    let chr = chr.as_char();
    !(chr == '\\'
        || chr == ':'
        || chr == '\r'
        || chr == '\n'
        || chr == ' '
        || chr == '\0')
}

fn is_space<C: AsChar>(chr: C) -> bool {
    let chr = chr.as_char();
    chr == ' ' || chr == '\t'
}

fn is_rule_separator<C: AsChar>(chr: C) -> bool {
    let chr = chr.as_char();
    chr == '\n' || chr == '\r' || is_space(chr)
}

named!(pub filename<&str, String>,
    escaped_transform!(
        take_while1!(is_file_name),
        '\\',
        alt!(
            tag!("\\") => { |_| "\\" }
            | tag!(" ") => { |_| " " }
            | tag!("r") => { |_| "\r" }
            | tag!("n") => { |_| "\n" }
            | tag!("t") => { |_| "\t" }
            | nom::character::complete::line_ending => { |_| "" }
        )
    )
);

named!(make_targets<&str, Vec<String>>,
    separated_list!(
        escaped!(
            take_while1!(is_space),
            '\\',
            nom::character::complete::line_ending
        ),
        filename
    )
);

named!(make_rule<&str, MakeRule>,
    do_parse!(
        targets: make_targets >>
        take_while!(is_space) >>
        tag!(":") >>
        take_while!(is_space) >>
        prereqs: make_targets >>
        (MakeRule { targets, prereqs })
    )
);

named!(make_rules<&str, Vec<MakeRule>>,
    delimited!(
        nom::character::complete::multispace0,
        separated_list!(
            take_while!(is_rule_separator),
            make_rule
        ),
        nom::character::complete::multispace0
    )
);

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

    #[test]
    fn it_works() {
        assert_eq!(
            filename("\\nfoo\\\\bar\\t\\ baz.o\0"),
            Ok(("\0", String::from("\nfoo\\bar\t baz.o")))
        );

        assert_eq!(
            filename("foo\\\nbar.o\0"),
            Ok(("\0", String::from("foobar.o")))
        );

        assert_eq!(
            filename("foo\\\r\nbar.o\0"),
            Ok(("\0", String::from("foobar.o")))
        );

        assert_eq!(
            make_targets("foo\\ ooo.o bar.o      baz.o:"),
            Ok((
                ":",
                vec!["foo ooo.o".into(), "bar.o".into(), "baz.o".into()]
            ))
        );

        assert_eq!(
            make_rule("foo.o bar.o   :  foo.c \\\n \\\r\n bar.c \n"),
            Ok((
                " \n",
                MakeRule {
                    targets: vec!["foo.o".into(), "bar.o".into()],
                    prereqs: vec!["foo.c".into(), "bar.c".into()],
                }
            ))
        );

        let makefile =
            "foo.o: foo.c foo.h  \t\n  \n\r\n bar.o: bar.c foo.h\n\0";

        assert_eq!(
            make_rules(makefile),
            Ok((
                "\0",
                vec![
                    MakeRule {
                        targets: vec!["foo.o".into()],
                        prereqs: vec!["foo.c".into(), "foo.h".into()],
                    },
                    MakeRule {
                        targets: vec!["bar.o".into()],
                        prereqs: vec!["bar.c".into(), "foo.h".into()],
                    }
                ]
            ))
        );

        assert_eq!(
            make_rules("obj/bar.o: src/bar.c src/foo.h\r\n\0"),
            Ok((
                "\0",
                vec![MakeRule {
                    targets: vec!["obj/bar.o".into()],
                    prereqs: vec!["src/bar.c".into(), "src/foo.h".into()],
                },]
            ))
        );
    }
}
<|endoftext|>


<commit_before>use helpers::*;
use core::intrinsics;

#[repr(C, packed)]
struct Nvic {
    iser: [u32; 7],
    _reserved1: [u32; 25],
    icer: [u32; 7],
    _reserved2: [u32; 25],
    ispr: [u32; 7],
    _reserved3: [u32; 25],
    icpr: [u32; 7]

}

#[repr(C)]
#[derive(Copy,Clone)]
pub enum NvicIdx {
    HFLASHC,
    PDCA0,
    PDCA1,
    PDCA2,
    PDCA3,
    PDCA4,
    PDCA5,
    PDCA6,
    PDCA7,
    PDCA8,
    PDCA9,
    PDCA10,
    PDCA11,
    PDCA12,
    PDCA13,
    PDCA14,
    PDCA15,
    CRCCU,
    USBC,
    PEVCTR,
    PEVCOV,
    AESA,
    PM,
    SCIF,
    FREQM,
    GPIO0,
    GPIO1,
    GPIO2,
    GPIO3,
    GPIO4,
    GPIO5,
    GPIO6,
    GPIO7,
    GPIO8,
    GPIO9,
    GPIO10,
    GPIO11,
    BPM,
    BSCIF,
    ASTALARM,
    ASTPER,
    ASTOVF,
    ASTREADY,
    ASTCLKREADY,
    WDT,
    EIC1,
    EIC2,
    EIC3,
    EIC4,
    EIC5,
    EIC6,
    EIC7,
    EIC8,
    IISC,
    SPI,
    TC00,
    TC01,
    TC02,
    TC10,
    TC11,
    TC12,
    TWIM0,
    TWIS0,
    TWIM1,
    TWIS1,
    USART0,
    USART1,
    USART2,
    USART3,
    ADCIFE,
    DACC,
    ACIFC,
    TRNG,
    PARC,
    CATB,
    TWIM2,
    TWIM3,
    LCDCA
}

impl ::core::default::Default for NvicIdx {
    fn default() -> NvicIdx {
        NvicIdx::HFLASHC
    }
}

pub const BASE_ADDRESS : usize = 0xe000e100;

pub unsafe fn enable(signal: NvicIdx) {
    let nvic : &mut Nvic = intrinsics::transmute(BASE_ADDRESS);
    let interrupt = signal as usize;

    volatile_store(&mut nvic.iser[interrupt / 32], 1 << (interrupt & 31));
}

pub unsafe fn disable(signal: NvicIdx) {
    let nvic : &mut Nvic = intrinsics::transmute(BASE_ADDRESS);
    let interrupt = signal as usize;

    volatile_store(&mut nvic.icer[interrupt / 32], 1 << (interrupt & 31));
}

pub unsafe fn clear_pending(signal: NvicIdx) {
    let nvic : &mut Nvic = intrinsics::transmute(BASE_ADDRESS);
    let interrupt = signal as usize;

    volatile_store(&mut nvic.icpr[interrupt / 32], 1 << (interrupt & 31));
}

<commit_msg>sam4l: Fix NvicIdx enum<commit_after>use helpers::*;
use core::intrinsics;

#[repr(C, packed)]
struct Nvic {
    iser: [u32; 7],
    _reserved1: [u32; 25],
    icer: [u32; 7],
    _reserved2: [u32; 25],
    ispr: [u32; 7],
    _reserved3: [u32; 25],
    icpr: [u32; 7]

}

#[repr(C)]
#[derive(Copy,Clone)]
pub enum NvicIdx {
    HFLASHC,
    PDCA0,
    PDCA1,
    PDCA2,
    PDCA3,
    PDCA4,
    PDCA5,
    PDCA6,
    PDCA7,
    PDCA8,
    PDCA9,
    PDCA10,
    PDCA11,
    PDCA12,
    PDCA13,
    PDCA14,
    PDCA15,
    CRCCU,
    USBC,
    PEVCTR,
    PEVCOV,
    AESA,
    PM,
    SCIF,
    FREQM,
    GPIO0,
    GPIO1,
    GPIO2,
    GPIO3,
    GPIO4,
    GPIO5,
    GPIO6,
    GPIO7,
    GPIO8,
    GPIO9,
    GPIO10,
    GPIO11,
    BPM,
    BSCIF,
    ASTALARM,
    ASTPER,
    ASTOVF,
    ASTREADY,
    ASTCLKREADY,
    WDT,
    EIC1,
    EIC2,
    EIC3,
    EIC4,
    EIC5,
    EIC6,
    EIC7,
    EIC8,
    IISC,
    SPI,
    TC00,
    TC01,
    TC02,
    TC10,
    TC11,
    TC12,
    TWIM0,
    TWIS0,
    TWIM1,
    TWIS1,
    USART0,
    USART1,
    USART2,
    USART3,
    ADCIFE,
    DACC,
    ACIFC,
    ABDACB,
    TRNG,
    PARC,
    CATB,
    _RESERVED,
    TWIM2,
    TWIM3,
    LCDCA
}

impl ::core::default::Default for NvicIdx {
    fn default() -> NvicIdx {
        NvicIdx::HFLASHC
    }
}

pub const BASE_ADDRESS : usize = 0xe000e100;

pub unsafe fn enable(signal: NvicIdx) {
    let nvic : &mut Nvic = intrinsics::transmute(BASE_ADDRESS);
    let interrupt = signal as usize;

    volatile_store(&mut nvic.iser[interrupt / 32], 1 << (interrupt & 31));
}

pub unsafe fn disable(signal: NvicIdx) {
    let nvic : &mut Nvic = intrinsics::transmute(BASE_ADDRESS);
    let interrupt = signal as usize;

    volatile_store(&mut nvic.icer[interrupt / 32], 1 << (interrupt & 31));
}

pub unsafe fn clear_pending(signal: NvicIdx) {
    let nvic : &mut Nvic = intrinsics::transmute(BASE_ADDRESS);
    let interrupt = signal as usize;

    volatile_store(&mut nvic.icpr[interrupt / 32], 1 << (interrupt & 31));
}

<|endoftext|>


<commit_before>use eyre::{bail, Result};
use regex::Regex;
use schemars::{schema_for, JsonSchema};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::{collections::HashMap, str::FromStr};
use std::{
    fs,
    path::{Path, PathBuf},
};
use strum::{EnumString, EnumVariantNames, ToString, VariantNames};

/// # A file or directory within a project
#[skip_serializing_none]
#[derive(Debug, Default, Clone, JsonSchema, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct File {
    /// The relative path of the file within the project folder
    path: String,

    /// Whether the entry is a directory or not
    is_dir: bool,

    /// The media type (aka MIME type) of the file
    media_type: Option<String>,

    /// The SHA1 hash of the contents of the file
    sha1: Option<String>,
}

impl File {
    pub fn from_path(folder: &Path, path: &Path) -> (PathBuf, File) {
        let canonical_path = path.canonicalize().expect("Unable to canonicalize path");
        let relative_path = path
            .strip_prefix(folder)
            .expect("Unable to strip prefix")
            .display()
            .to_string();

        let media_type = mime_guess::from_path(path)
            .first()
            .map(|mime| mime.essence_str().to_string());

        let file = File {
            path: relative_path,
            is_dir: path.is_dir(),
            media_type,
            ..Default::default()
        };

        (canonical_path, file)
    }
}

/// # Details of a project
///
/// An implementation, and extension, of schema.org [`Project`](https://schema.org/Project).
/// Uses schema.org properties where possible but adds extension properties
/// where needed (e.g. `theme`).
#[skip_serializing_none]
#[derive(Debug, Default, Clone, JsonSchema, Deserialize, Serialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Project {
    /// The name of the project
    name: Option<String>,

    /// A description of the project
    description: Option<String>,

    /// URL of the image to be used when displaying the project
    ///
    /// If not specified, will default to the most recently
    /// modified image in the project (if any).
    image: Option<String>,

    /// The path (within the project) of the project's main file
    ///
    /// If not specified, will default to the first file matching the
    /// the regular expression in the configuration settings.
    main: Option<String>,

    /// The default theme to use when viewing documents in this project
    ///
    /// If not specified, will default to the default theme in the
    /// configuration settings.
    theme: Option<String>,

    /// The files in the project directory
    files: HashMap<PathBuf, File>,
}

/// A format to display a plugin using
#[derive(Debug, EnumString, EnumVariantNames, PartialEq, ToString)]
#[strum(serialize_all = "lowercase")]
pub enum ShowFormat {
    Md,
    Toml,
    Json,
}

impl Project {
    /// The name of the project's manifest file within the project directory
    const FILE_NAME: &'static str = "project.json";

    /// Get the JSON Schema for a project
    pub fn schema() -> String {
        let schema = schema_for!(Project);
        serde_json::to_string_pretty(&schema).unwrap()
    }

    /// Get the path to a projects' manifest file
    fn file(folder: &str) -> PathBuf {
        Path::new(folder).join(Project::FILE_NAME)
    }

    /// Read a project's manifest file
    ///
    /// If there is no manifest file, then return a default project
    fn read(folder: &str) -> Result<Project> {
        if !Path::new(folder).exists() {
            bail!("Project folder does not exist: {}", folder)
        }

        let file = Project::file(folder);
        let project = if file.exists() {
            let json = fs::read_to_string(file)?;
            serde_json::from_str(&json)?
        } else {
            Project::default()
        };

        Ok(project)
    }

    /// Write a project's manifest file
    ///
    /// If the project folder does not exist yet then it will be created
    pub fn write(folder: &str, project: &Project) -> Result<()> {
        fs::create_dir_all(folder)?;

        let file = Project::file(folder);
        let json = serde_json::to_string_pretty(project)?;
        fs::write(file, json)?;

        Ok(())
    }

    /// Initialize a project in a new, or existing, folder
    ///
    /// If the project has already been initialized (i.e. has a manifest file)
    /// then this function will do nothing
    pub fn init(folder: &str) -> Result<Project> {
        if Project::file(folder).exists() {
            return Project::read(folder);
        }

        let project = Project::default();
        Project::write(folder, &project)?;

        Ok(project)
    }

    /// Load a project including creating default values for properties
    /// where necessary
    pub fn load(folder: &str, config: &config::ProjectsConfig) -> Result<Project> {
        let project = Project::read(folder)?;
        let Project {
            name, main, theme, ..
        } = project;

        // Name defaults to the name of the folder
        let name = name.or_else(|| match Path::new(folder).components().last() {
            Some(last) => Some(last.as_os_str().to_string_lossy().to_string()),
            None => Some("Unnamed".to_string()),
        });

        // Get all the files in the project
        let folder = Path::new(folder);
        let files: Vec<(PathBuf, File)> = walkdir::WalkDir::new(folder)
            .into_iter()
            .filter_map(|entry| {
                let entry = match entry.ok() {
                    Some(entry) => entry,
                    None => return None,
                };
                Some(File::from_path(folder, entry.path()))
            })
            .collect();

        // Main defaults to the first file that matches configured patterns (if any)
        let main = main.or_else(|| {
            // See if there are any files matching patterns
            for pattern in &config.main_patterns {
                let re = match Regex::new(&pattern.to_lowercase()) {
                    Ok(re) => re,
                    Err(_) => {
                        tracing::warn!("Project main file pattern is invalid: {}", pattern);
                        continue;
                    }
                };
                for (_, file) in &files {
                    let File { is_dir, path, .. } = file;
                    if *is_dir {
                        continue;
                    }
                    if re.is_match(path) {
                        return Some(path.clone());
                    }
                }
            }

            None
        });

        let files = files.into_iter().collect();

        // Name defaults to the configured default
        let theme = theme.or_else(|| Some(config.theme.clone()));

        Ok(Project {
            name,
            main,
            theme,
            files,
            ..project
        })
    }

    /// Show a project in a format
    ///
    /// Used for displaying a project in CLI and possibly elsewhere.
    pub fn show(&self, format: ShowFormat) -> Result<(String, String)> {
        let content = match format {
            ShowFormat::Json => serde_json::to_string_pretty(self)?,
            ShowFormat::Toml => toml::to_string(self)?,
            ShowFormat::Md => {
                use handlebars::Handlebars;

                let template = r#"
# {{name}}

**Main**: {{ main }}
**Theme**: {{ theme }}

"#;
                let hb = Handlebars::new();
                hb.render_template(template.trim(), self)?
            }
        };

        Ok((format.to_string(), content))
    }
}

/// An in-memory store of projects and associated
/// data (e.g. file system watchers)
#[derive(Debug, Deserialize)]
#[serde(default)]
pub struct Projects {
    /// The projects, stored by absolute path
    pub projects: HashMap<String, Project>,
}

impl Default for Projects {
    fn default() -> Self {
        Projects {
            projects: HashMap::new(),
        }
    }
}

impl Projects {
    /// Get the canonical absolute path of a project folder
    fn path(folder: &str) -> Result<String> {
        Ok(Path::new(folder).canonicalize()?.display().to_string())
    }

    /// List projects that are open
    pub fn list(&self) -> Result<HashMap<String, Project>> {
        Ok(self.projects.clone())
    }

    /// Open a project
    ///
    /// This function `loads` a project, stores it, watches the project folder,
    /// updates the project on changes and publishes the updates on the "projects"
    /// pubsub topic channel.
    pub fn open(
        &mut self,
        folder: &str,
        config: &config::ProjectsConfig,
    ) -> Result<(String, Project)> {
        let path = Projects::path(folder)?;
        let project = Project::load(folder, config)?;
        self.projects.insert(path.clone(), project.clone());
        Ok((path, project))
    }

    /// Close a project
    pub fn close(&mut self, folder: &str) -> Result<()> {
        let path = Projects::path(folder)?;
        self.projects.remove(&path);
        Ok(())
    }
}

#[cfg(feature = "config")]
pub mod config {
    use super::*;
    use defaults::Defaults;
    use validator::Validate;

    /// # Projects
    ///
    /// Configuration settings for project defaults
    #[derive(Debug, Defaults, PartialEq, Clone, JsonSchema, Deserialize, Serialize, Validate)]
    #[serde(default, rename_all = "camelCase")]
    pub struct ProjectsConfig {
        /// Patterns used to infer the main file of projects
        ///
        /// For projects that do not specify a main file, each file is tested
        /// against these case insensitive patterns in order. The first
        /// file (alphabetically) that matches is the project's main file.
        #[def = r#"vec!["^main\\b".to_string(), "^index\\b".to_string(), "^readme\\b".to_string()]"#]
        pub main_patterns: Vec<String>,

        /// Default project theme
        ///
        /// Will be applied to all projects that do not specify a theme
        #[def = r#"String::from("stencila")"#]
        pub theme: String,
    }
}

#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use structopt::StructOpt;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Initialize a project in a new, or existing, folder",
        setting = structopt::clap::AppSettings::DeriveDisplayOrder,
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Init {
        /// The path of the new, or existing, folder to initialize
        ///
        /// If no folder exists at the path, then one will be created.
        /// If no `project.json` file exists in the folder then a new one
        /// will be created.
        #[structopt(default_value = ".")]
        pub folder: String,
    }

    impl Init {
        pub fn run(&self) -> Result<()> {
            let Self { folder } = self;
            Project::init(folder)?;
            Ok(())
        }
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Show a project details",
        setting = structopt::clap::AppSettings::DeriveDisplayOrder,
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Show {
        /// The path of the project folder
        #[structopt(default_value = ".")]
        pub folder: String,

        /// The format to display the project in
        #[structopt(short, long, default_value = "md", possible_values = ShowFormat::VARIANTS, case_insensitive = true)]
        pub format: String,
    }

    impl Show {
        pub fn run(&self, config: &config::ProjectsConfig) -> Result<(String, String)> {
            let Self { folder, format } = self;
            let format = ShowFormat::from_str(&format)?;
            Project::load(folder, config)?.show(format)
        }
    }
}
<commit_msg>fix(Files): Use a BTreeMap and ignore project folder<commit_after>use eyre::{bail, Result};
use regex::Regex;
use schemars::{schema_for, JsonSchema};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::{collections::{BTreeMap, HashMap}, str::FromStr};
use std::{
    fs,
    path::{Path, PathBuf},
};
use strum::{EnumString, EnumVariantNames, ToString, VariantNames};

/// # A file or directory within a project
#[skip_serializing_none]
#[derive(Debug, Default, Clone, JsonSchema, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct File {
    /// The relative path of the file within the project folder
    path: String,

    /// Whether the entry is a directory or not
    is_dir: bool,

    /// The media type (aka MIME type) of the file
    media_type: Option<String>,

    /// The SHA1 hash of the contents of the file
    sha1: Option<String>,
}

impl File {
    pub fn from_path(folder: &Path, path: &Path) -> (PathBuf, File) {
        let canonical_path = path.canonicalize().expect("Unable to canonicalize path");
        let relative_path = path
            .strip_prefix(folder)
            .expect("Unable to strip prefix")
            .display()
            .to_string();

        let media_type = mime_guess::from_path(path)
            .first()
            .map(|mime| mime.essence_str().to_string());

        let file = File {
            path: relative_path,
            is_dir: path.is_dir(),
            media_type,
            ..Default::default()
        };

        (canonical_path, file)
    }
}

/// # Details of a project
///
/// An implementation, and extension, of schema.org [`Project`](https://schema.org/Project).
/// Uses schema.org properties where possible but adds extension properties
/// where needed (e.g. `theme`).
#[skip_serializing_none]
#[derive(Debug, Default, Clone, JsonSchema, Deserialize, Serialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Project {
    /// The name of the project
    name: Option<String>,

    /// A description of the project
    description: Option<String>,

    /// URL of the image to be used when displaying the project
    ///
    /// If not specified, will default to the most recently
    /// modified image in the project (if any).
    image: Option<String>,

    /// The path (within the project) of the project's main file
    ///
    /// If not specified, will default to the first file matching the
    /// the regular expression in the configuration settings.
    main: Option<String>,

    /// The default theme to use when viewing documents in this project
    ///
    /// If not specified, will default to the default theme in the
    /// configuration settings.
    theme: Option<String>,

    /// The files in the project directory
    files: BTreeMap<PathBuf, File>,
}

/// A format to display a plugin using
#[derive(Debug, EnumString, EnumVariantNames, PartialEq, ToString)]
#[strum(serialize_all = "lowercase")]
pub enum ShowFormat {
    Md,
    Toml,
    Json,
}

impl Project {
    /// The name of the project's manifest file within the project directory
    const FILE_NAME: &'static str = "project.json";

    /// Get the JSON Schema for a project
    pub fn schema() -> String {
        let schema = schema_for!(Project);
        serde_json::to_string_pretty(&schema).unwrap()
    }

    /// Get the path to a projects' manifest file
    fn file(folder: &str) -> PathBuf {
        Path::new(folder).join(Project::FILE_NAME)
    }

    /// Read a project's manifest file
    ///
    /// If there is no manifest file, then return a default project
    fn read(folder: &str) -> Result<Project> {
        if !Path::new(folder).exists() {
            bail!("Project folder does not exist: {}", folder)
        }

        let file = Project::file(folder);
        let project = if file.exists() {
            let json = fs::read_to_string(file)?;
            serde_json::from_str(&json)?
        } else {
            Project::default()
        };

        Ok(project)
    }

    /// Write a project's manifest file
    ///
    /// If the project folder does not exist yet then it will be created
    pub fn write(folder: &str, project: &Project) -> Result<()> {
        fs::create_dir_all(folder)?;

        let file = Project::file(folder);
        let json = serde_json::to_string_pretty(project)?;
        fs::write(file, json)?;

        Ok(())
    }

    /// Initialize a project in a new, or existing, folder
    ///
    /// If the project has already been initialized (i.e. has a manifest file)
    /// then this function will do nothing
    pub fn init(folder: &str) -> Result<Project> {
        if Project::file(folder).exists() {
            return Project::read(folder);
        }

        let project = Project::default();
        Project::write(folder, &project)?;

        Ok(project)
    }

    /// Load a project including creating default values for properties
    /// where necessary
    pub fn load(folder: &str, config: &config::ProjectsConfig) -> Result<Project> {
        let project = Project::read(folder)?;
        let Project {
            name, main, theme, ..
        } = project;

        // Name defaults to the name of the folder
        let name = name.or_else(|| match Path::new(folder).components().last() {
            Some(last) => Some(last.as_os_str().to_string_lossy().to_string()),
            None => Some("Unnamed".to_string()),
        });

        // Get all the files in the project (use `min_depth` to ignore the folder itself)
        let folder = Path::new(folder);
        let files: Vec<(PathBuf, File)> = walkdir::WalkDir::new(folder).min_depth(1)
            .into_iter()
            .filter_map(|entry| {
                let entry = match entry.ok() {
                    Some(entry) => entry,
                    None => return None,
                };
                Some(File::from_path(folder, entry.path()))
            })
            .collect();

        // Main defaults to the first file that matches configured patterns (if any)
        let main = main.or_else(|| {
            // See if there are any files matching patterns
            for pattern in &config.main_patterns {
                let re = match Regex::new(&pattern.to_lowercase()) {
                    Ok(re) => re,
                    Err(_) => {
                        tracing::warn!("Project main file pattern is invalid: {}", pattern);
                        continue;
                    }
                };
                for (_, file) in &files {
                    let File { is_dir, path, .. } = file;
                    if *is_dir {
                        continue;
                    }
                    if re.is_match(path) {
                        return Some(path.clone());
                    }
                }
            }

            None
        });

        let files = files.into_iter().collect();

        // Name defaults to the configured default
        let theme = theme.or_else(|| Some(config.theme.clone()));

        Ok(Project {
            name,
            main,
            theme,
            files,
            ..project
        })
    }

    /// Show a project in a format
    ///
    /// Used for displaying a project in CLI and possibly elsewhere.
    pub fn show(&self, format: ShowFormat) -> Result<(String, String)> {
        let content = match format {
            ShowFormat::Json => serde_json::to_string_pretty(self)?,
            ShowFormat::Toml => toml::to_string(self)?,
            ShowFormat::Md => {
                use handlebars::Handlebars;

                let template = r#"
# {{name}}

**Main**: {{ main }}
**Theme**: {{ theme }}

"#;
                let hb = Handlebars::new();
                hb.render_template(template.trim(), self)?
            }
        };

        Ok((format.to_string(), content))
    }
}

/// An in-memory store of projects and associated
/// data (e.g. file system watchers)
#[derive(Debug, Deserialize)]
#[serde(default)]
pub struct Projects {
    /// The projects, stored by absolute path
    pub projects: HashMap<String, Project>,
}

impl Default for Projects {
    fn default() -> Self {
        Projects {
            projects: HashMap::new(),
        }
    }
}

impl Projects {
    /// Get the canonical absolute path of a project folder
    fn path(folder: &str) -> Result<String> {
        Ok(Path::new(folder).canonicalize()?.display().to_string())
    }

    /// List projects that are open
    pub fn list(&self) -> Result<HashMap<String, Project>> {
        Ok(self.projects.clone())
    }

    /// Open a project
    ///
    /// This function `loads` a project, stores it, watches the project folder,
    /// updates the project on changes and publishes the updates on the "projects"
    /// pubsub topic channel.
    pub fn open(
        &mut self,
        folder: &str,
        config: &config::ProjectsConfig,
    ) -> Result<(String, Project)> {
        let path = Projects::path(folder)?;
        let project = Project::load(folder, config)?;
        self.projects.insert(path.clone(), project.clone());
        Ok((path, project))
    }

    /// Close a project
    pub fn close(&mut self, folder: &str) -> Result<()> {
        let path = Projects::path(folder)?;
        self.projects.remove(&path);
        Ok(())
    }
}

#[cfg(feature = "config")]
pub mod config {
    use super::*;
    use defaults::Defaults;
    use validator::Validate;

    /// # Projects
    ///
    /// Configuration settings for project defaults
    #[derive(Debug, Defaults, PartialEq, Clone, JsonSchema, Deserialize, Serialize, Validate)]
    #[serde(default, rename_all = "camelCase")]
    pub struct ProjectsConfig {
        /// Patterns used to infer the main file of projects
        ///
        /// For projects that do not specify a main file, each file is tested
        /// against these case insensitive patterns in order. The first
        /// file (alphabetically) that matches is the project's main file.
        #[def = r#"vec!["^main\\b".to_string(), "^index\\b".to_string(), "^readme\\b".to_string()]"#]
        pub main_patterns: Vec<String>,

        /// Default project theme
        ///
        /// Will be applied to all projects that do not specify a theme
        #[def = r#"String::from("stencila")"#]
        pub theme: String,
    }
}

#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use structopt::StructOpt;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Initialize a project in a new, or existing, folder",
        setting = structopt::clap::AppSettings::DeriveDisplayOrder,
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Init {
        /// The path of the new, or existing, folder to initialize
        ///
        /// If no folder exists at the path, then one will be created.
        /// If no `project.json` file exists in the folder then a new one
        /// will be created.
        #[structopt(default_value = ".")]
        pub folder: String,
    }

    impl Init {
        pub fn run(&self) -> Result<()> {
            let Self { folder } = self;
            Project::init(folder)?;
            Ok(())
        }
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Show a project details",
        setting = structopt::clap::AppSettings::DeriveDisplayOrder,
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Show {
        /// The path of the project folder
        #[structopt(default_value = ".")]
        pub folder: String,

        /// The format to display the project in
        #[structopt(short, long, default_value = "md", possible_values = ShowFormat::VARIANTS, case_insensitive = true)]
        pub format: String,
    }

    impl Show {
        pub fn run(&self, config: &config::ProjectsConfig) -> Result<(String, String)> {
            let Self { folder, format } = self;
            let format = ShowFormat::from_str(&format)?;
            Project::load(folder, config)?.show(format)
        }
    }
}
<|endoftext|>


<commit_before>// no-system-llvm
// compile-flags: -O
// only-64bit (because the LLVM type of i64 for usize shows up)

#![crate_type = "lib"]
#![feature(slice_as_chunks)]

// CHECK-LABEL: @chunks4
#[no_mangle]
pub fn chunks4(x: &[u8]) -> &[[u8; 4]] {
    // CHECK-NEXT: start:
    // CHECK-NEXT: lshr i64 %x.1, 2
    // CHECK-NOT: shl
    // CHECK-NOT: mul
    // CHECK-NOT: udiv
    // CHECK-NOT: urem
    // CHECK: ret
    x.as_chunks().0
}

// CHECK-LABEL: @chunks4_with_remainder
#[no_mangle]
pub fn chunks4_with_remainder(x: &[u8]) -> (&[[u8; 4]], &[u8]) {
    // CHECK: and i64 %x.1, -4
    // CHECK: and i64 %x.1, 3
    // CHECK: lshr exact
    // CHECK-NOT: mul
    // CHECK-NOT: udiv
    // CHECK-NOT: urem
    // CHECK: ret
    x.as_chunks()
}
<commit_msg>Try ignore-debug in the codegen test<commit_after>// no-system-llvm
// compile-flags: -O
// only-64bit (because the LLVM type of i64 for usize shows up)
// ignore-debug: the debug assertions get in the way

#![crate_type = "lib"]
#![feature(slice_as_chunks)]

// CHECK-LABEL: @chunks4
#[no_mangle]
pub fn chunks4(x: &[u8]) -> &[[u8; 4]] {
    // CHECK-NEXT: start:
    // CHECK-NEXT: lshr i64 %x.1, 2
    // CHECK-NOT: shl
    // CHECK-NOT: mul
    // CHECK-NOT: udiv
    // CHECK-NOT: urem
    // CHECK: ret
    x.as_chunks().0
}

// CHECK-LABEL: @chunks4_with_remainder
#[no_mangle]
pub fn chunks4_with_remainder(x: &[u8]) -> (&[[u8; 4]], &[u8]) {
    // CHECK: and i64 %x.1, -4
    // CHECK: and i64 %x.1, 3
    // CHECK: lshr exact
    // CHECK-NOT: mul
    // CHECK-NOT: udiv
    // CHECK-NOT: urem
    // CHECK: ret
    x.as_chunks()
}
<|endoftext|>


<commit_before>use std::f64;
use rand::Rng;
use error::StatsError;
use function::gamma;
use result::Result;
use super::{Distribution, Univariate, Continuous};
use super::normal;

#[derive(Debug, Clone, PartialEq)]
pub struct Chi {
    k: f64,
}

impl Chi {
    pub fn new(freedom: f64) -> Result<Chi> {
        if freedom.is_nan() || freedom <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            Ok(Chi { k: freedom })
        }
    }

    pub fn freedom(&self) -> f64 {
        self.k
    }
}

impl Distribution for Chi {
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        (0..self.k.floor() as i64)
            .fold(0.0,
                  |acc, _| acc + normal::sample_unchecked(r, 0.0, 1.0).powf(2.0))
            .sqrt()
    }
}

impl Univariate for Chi {
    fn mean(&self) -> f64 {
        f64::consts::SQRT_2 * gamma::gamma((self.k + 1.0) / 2.0) / gamma::gamma(self.k / 2.0)
    }

    fn variance(&self) -> f64 {
        self.k - self.mean() * self.mean()
    }

    fn std_dev(&self) -> f64 {
        self.variance().sqrt()
    }

    fn entropy(&self) -> f64 {
        gamma::ln_gamma(self.k / 2.0) +
        (self.k - (2.0f64).ln() - (self.k - 1.0) * gamma::digamma(self.k / 2.0).unwrap()) / 2.0
    }

    fn skewness(&self) -> f64 {
        let sigma = self.std_dev();
        self.mean() * (1.0 - 2.0 * sigma * sigma) / (sigma * sigma * sigma)
    }

    fn median(&self) -> f64 {
        unimplemented!()
    }

    fn cdf(&self, x: f64) -> f64 {
        if x == f64::INFINITY || self.k == f64::INFINITY {
            1.0
        } else {
            gamma::gamma_lr(self.k / 2.0, x * x / 2.0).unwrap()
        }
    }
}

impl Continuous for Chi {
    fn mode(&self) -> f64 {
        if self.k < 1.0 {
            panic!("Cannot calculate Chi distribution mode for freedom < 1");
        }
        (self.k - 1.0).sqrt()
    }

    fn min(&self) -> f64 {
        0.0
    }

    fn max(&self) -> f64 {
        f64::INFINITY
    }

    fn pdf(&self, x: f64) -> f64 {
        match (self.k, x) {
            (f64::INFINITY, _) | (_, f64::INFINITY) | (_, 0.0) => 0.0,
            (_, _) if self.k > 160.0 => self.ln_pdf(x),
            (_, _) => {
                (2.0f64).powf(1.0 - self.k / 2.0) * x.powf(self.k - 1.0) * (-x * x / 2.0).exp() /
                gamma::gamma(self.k / 2.0)
            }
        }
    }

    fn ln_pdf(&self, x: f64) -> f64 {
        match (self.k, x) {
            (f64::INFINITY, _) | (_, f64::INFINITY) | (_, 0.0) => f64::NEG_INFINITY,
            (_, _) => {
                (1.0 - self.k / 2.0) * (2.0f64).ln() + ((self.k - 1.0) * x.ln()) - x * x / 2.0 -
                gamma::ln_gamma(self.k / 2.0)
            }
        }
    }
}
<commit_msg>floor call for Chi sample unnecessary<commit_after>use std::f64;
use rand::Rng;
use error::StatsError;
use function::gamma;
use result::Result;
use super::{Distribution, Univariate, Continuous};
use super::normal;

#[derive(Debug, Clone, PartialEq)]
pub struct Chi {
    k: f64,
}

impl Chi {
    pub fn new(freedom: f64) -> Result<Chi> {
        if freedom.is_nan() || freedom <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            Ok(Chi { k: freedom })
        }
    }

    pub fn freedom(&self) -> f64 {
        self.k
    }
}

impl Distribution for Chi {
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        (0..self.k as i64)
            .fold(0.0,
                  |acc, _| acc + normal::sample_unchecked(r, 0.0, 1.0).powf(2.0))
            .sqrt()
    }
}

impl Univariate for Chi {
    fn mean(&self) -> f64 {
        f64::consts::SQRT_2 * gamma::gamma((self.k + 1.0) / 2.0) / gamma::gamma(self.k / 2.0)
    }

    fn variance(&self) -> f64 {
        self.k - self.mean() * self.mean()
    }

    fn std_dev(&self) -> f64 {
        self.variance().sqrt()
    }

    fn entropy(&self) -> f64 {
        gamma::ln_gamma(self.k / 2.0) +
        (self.k - (2.0f64).ln() - (self.k - 1.0) * gamma::digamma(self.k / 2.0).unwrap()) / 2.0
    }

    fn skewness(&self) -> f64 {
        let sigma = self.std_dev();
        self.mean() * (1.0 - 2.0 * sigma * sigma) / (sigma * sigma * sigma)
    }

    fn median(&self) -> f64 {
        unimplemented!()
    }

    fn cdf(&self, x: f64) -> f64 {
        if x == f64::INFINITY || self.k == f64::INFINITY {
            1.0
        } else {
            gamma::gamma_lr(self.k / 2.0, x * x / 2.0).unwrap()
        }
    }
}

impl Continuous for Chi {
    fn mode(&self) -> f64 {
        if self.k < 1.0 {
            panic!("Cannot calculate Chi distribution mode for freedom < 1");
        }
        (self.k - 1.0).sqrt()
    }

    fn min(&self) -> f64 {
        0.0
    }

    fn max(&self) -> f64 {
        f64::INFINITY
    }

    fn pdf(&self, x: f64) -> f64 {
        match (self.k, x) {
            (f64::INFINITY, _) | (_, f64::INFINITY) | (_, 0.0) => 0.0,
            (_, _) if self.k > 160.0 => self.ln_pdf(x),
            (_, _) => {
                (2.0f64).powf(1.0 - self.k / 2.0) * x.powf(self.k - 1.0) * (-x * x / 2.0).exp() /
                gamma::gamma(self.k / 2.0)
            }
        }
    }

    fn ln_pdf(&self, x: f64) -> f64 {
        match (self.k, x) {
            (f64::INFINITY, _) | (_, f64::INFINITY) | (_, 0.0) => f64::NEG_INFINITY,
            (_, _) => {
                (1.0 - self.k / 2.0) * (2.0f64).ln() + ((self.k - 1.0) * x.ln()) - x * x / 2.0 -
                gamma::ln_gamma(self.k / 2.0)
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Defines an RGBA8-based texture and pixel format.
use crate::texture::{Pixel, Texture};

/// [Pixel] format for [MemoryRGBA8Texture].
#[derive(Copy, Clone)]
pub struct RGBA8 {
    /// Red component.
    pub r: u8,
    /// Green component.
    pub g: u8,
    /// Blue component.
    pub b: u8,
    /// Alpha component.
    pub a: u8,
}

impl Pixel for RGBA8 {
    fn is_transparent(&self) -> bool {
        self.a == 0
    }

    fn transparency() -> Option<Self> {
        Some(RGBA8 {
            r: 0,
            g: 0,
            b: 0,
            a: 0,
        })
    }

    fn outline() -> RGBA8 {
        RGBA8 {
            r: 255,
            g: 0,
            b: 0,
            a: 255,
        }
    }
}

/// Texture from RGBA8 pixel data.
pub struct MemoryRGBA8Texture {
    pixels: Vec<RGBA8>,
    width: u32,
    height: u32,
}

impl MemoryRGBA8Texture {
    /// Create a texture from memory given a raw buffer.
    pub fn from_memory(buf: &[u8], w: u32, h: u32) -> MemoryRGBA8Texture {
        let mut pixels = Vec::new();

        for pixel in buf.chunks(4) {
            pixels.push(RGBA8 {
                r: pixel[0],
                g: pixel[1],
                b: pixel[2],
                a: pixel[3],
            });
        }

        MemoryRGBA8Texture {
            pixels: pixels,
            width: w,
            height: h,
        }
    }

    #[inline(always)]
    fn index_for(&self, x: u32, y: u32) -> usize {
        (y * self.width + x) as usize
    }
}

impl Texture for MemoryRGBA8Texture {
    type Pixel = RGBA8;

    fn width(&self) -> u32 {
        self.width
    }

    fn height(&self) -> u32 {
        self.height
    }

    fn get(&self, x: u32, y: u32) -> Option<RGBA8> {
        if let Some(p) = self.pixels.get(self.index_for(x, y)) {
            Some(*p)
        } else {
            None
        }
    }

    fn set(&mut self, x: u32, y: u32, val: RGBA8) {
        let index = self.index_for(x, y);
        self.pixels[index] = val;
    }
}
<commit_msg>memory_rgba8: Panic on width/height pixeldata mismatch<commit_after>//! Defines an RGBA8-based texture and pixel format.
use crate::texture::{Pixel, Texture};

/// [Pixel] format for [MemoryRGBA8Texture].
#[derive(Copy, Clone)]
pub struct RGBA8 {
    /// Red component.
    pub r: u8,
    /// Green component.
    pub g: u8,
    /// Blue component.
    pub b: u8,
    /// Alpha component.
    pub a: u8,
}

impl Pixel for RGBA8 {
    fn is_transparent(&self) -> bool {
        self.a == 0
    }

    fn transparency() -> Option<Self> {
        Some(RGBA8 {
            r: 0,
            g: 0,
            b: 0,
            a: 0,
        })
    }

    fn outline() -> RGBA8 {
        RGBA8 {
            r: 255,
            g: 0,
            b: 0,
            a: 255,
        }
    }
}

/// Texture from RGBA8 pixel data.
pub struct MemoryRGBA8Texture {
    pixels: Vec<RGBA8>,
    width: u32,
    height: u32,
}

impl MemoryRGBA8Texture {
    /// Create a texture from memory given a raw buffer.
    pub fn from_memory(buf: &[u8], w: u32, h: u32) -> MemoryRGBA8Texture {
        let mut pixels = Vec::new();

        assert_eq!((buf.len() / 4) as u32, w * h, "buffer does not contain as many pixels ({}) as specified by the width and height ({}, {}) = {}", buf.len() / 4, w, h, w * h);

        for pixel in buf.chunks(4) {
            pixels.push(RGBA8 {
                r: pixel[0],
                g: pixel[1],
                b: pixel[2],
                a: pixel[3],
            });
        }

        MemoryRGBA8Texture {
            pixels: pixels,
            width: w,
            height: h,
        }
    }

    #[inline(always)]
    fn index_for(&self, x: u32, y: u32) -> usize {
        (y * self.width + x) as usize
    }
}

impl Texture for MemoryRGBA8Texture {
    type Pixel = RGBA8;

    fn width(&self) -> u32 {
        self.width
    }

    fn height(&self) -> u32 {
        self.height
    }

    fn get(&self, x: u32, y: u32) -> Option<RGBA8> {
        if let Some(p) = self.pixels.get(self.index_for(x, y)) {
            Some(*p)
        } else {
            None
        }
    }

    fn set(&mut self, x: u32, y: u32, val: RGBA8) {
        let index = self.index_for(x, y);
        self.pixels[index] = val;
    }
}

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

    #[test]
    #[should_panic(
        expected = "buffer does not contain as many pixels (0) as specified by the width and height (1, 1) = 1"
    )]
    fn input_data_not_divisible_by_4() {
        MemoryRGBA8Texture::from_memory(&[0], 1, 1);
    }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

use std::rc::Rc;
use syntax::ext::base::ExtCtxt;

use builder::{Builder, TokenString, add_node_dependency};
use node;

pub fn attach(builder: &mut Builder, _: &mut ExtCtxt, node: Rc<node::Node>) {
  node.materializer.set(Some(build_dht22));
  node.mutator.set(Some(mutate_pin));

  let pin_node_name = node.get_ref_attr("pin").unwrap();
  let pin_node = builder.pt.get_by_name(pin_node_name.as_slice()).unwrap();
  add_node_dependency(&node, &pin_node);

  let timer_node_name = node.get_ref_attr("timer").unwrap();
  let timer_node = builder.pt.get_by_name(timer_node_name.as_slice()).unwrap();
  add_node_dependency(&node, &timer_node);
}

fn mutate_pin(builder: &mut Builder, _: &mut ExtCtxt, node: Rc<node::Node>) {
  let pin_node_name = node.get_ref_attr("pin").unwrap();
  let pin_node = builder.pt.get_by_name(pin_node_name.as_slice()).unwrap();
  pin_node.attributes.borrow_mut().insert("direction".to_str(),
        Rc::new(node::Attribute::new_nosp(node::StrValue("out".to_str()))));
}

fn build_dht22(builder: &mut Builder, cx: &mut ExtCtxt, node: Rc<node::Node>) {
  if !node.expect_no_subnodes(cx) {return}

  if !node.expect_attributes(cx,
      [("pin", node::RefAttribute), ("timer", node::RefAttribute)]) {
    return
  }

  let pin_node_name = node.get_ref_attr("pin").unwrap();
  let timer_node_name = node.get_ref_attr("timer").unwrap();
  let pin_node = builder.pt.get_by_name(pin_node_name.as_slice()).unwrap();
  let timer_node = builder.pt.get_by_name(timer_node_name.as_slice()).unwrap();

  let pin = TokenString(pin_node_name);
  let timer = TokenString(timer_node_name);
  let name = TokenString(node.name.clone().unwrap());

  let typename = format!(
      "zinc::drivers::dht22::DHT22<'a, {}, {}>",
      timer_node.type_name().unwrap(),
      pin_node.type_name().unwrap());
  node.set_type_name(typename);

  let st = quote_stmt!(&*cx,
      let $name = zinc::drivers::dht22::DHT22::new(&$timer, &$pin);
  );
  builder.add_main_statement(st);
}

#[cfg(test)]
mod test {
  use builder::Builder;
  use test_helpers::{assert_equal_source, with_parsed};

  #[test]
  fn builds_lpc17xx_pt() {
    with_parsed("
      timer@timer;
      pin@pin;
      dht@dht22 {
        pin = &pin;
        timer = &timer;
      }", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      super::mutate_pin(&mut builder, cx, pt.get_by_name("dht").unwrap());
      super::build_dht22(&mut builder, cx, pt.get_by_name("dht").unwrap());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);

      assert_equal_source(builder.main_stmts.get(0),
          "let dht = zinc::drivers::dht22::DHT22::new(&timer, &pin);");

      let pin_node = pt.get_by_name("pin").unwrap();
      assert!(pin_node.get_string_attr("direction").unwrap() == "out".to_str());
    });
  }
}
<commit_msg>dht22pt kind of works<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

use std::rc::Rc;
use syntax::ext::base::ExtCtxt;

use builder::{Builder, TokenString, add_node_dependency};
use node;

pub fn attach(builder: &mut Builder, _: &mut ExtCtxt, node: Rc<node::Node>) {
  node.materializer.set(Some(build_dht22));
  node.mutator.set(Some(mutate_pin));

  let pin_node_name = node.get_ref_attr("pin").unwrap();
  let pin_node = builder.pt.get_by_name(pin_node_name.as_slice()).unwrap();
  add_node_dependency(&node, &pin_node);

  let timer_node_name = node.get_ref_attr("timer").unwrap();
  let timer_node = builder.pt.get_by_name(timer_node_name.as_slice()).unwrap();
  add_node_dependency(&node, &timer_node);
}

fn mutate_pin(builder: &mut Builder, _: &mut ExtCtxt, node: Rc<node::Node>) {
  let pin_node_name = node.get_ref_attr("pin").unwrap();
  let pin_node = builder.pt.get_by_name(pin_node_name.as_slice()).unwrap();
  pin_node.attributes.borrow_mut().insert("direction".to_str(),
        Rc::new(node::Attribute::new_nosp(node::StrValue("out".to_str()))));
}

fn build_dht22(builder: &mut Builder, cx: &mut ExtCtxt, node: Rc<node::Node>) {
  if !node.expect_no_subnodes(cx) {return}

  if !node.expect_attributes(cx,
      [("pin", node::RefAttribute), ("timer", node::RefAttribute)]) {
    return
  }

  let pin_node_name = node.get_ref_attr("pin").unwrap();
  let timer_node_name = node.get_ref_attr("timer").unwrap();
  let pin_node = builder.pt.get_by_name(pin_node_name.as_slice()).unwrap();
  let timer_node = builder.pt.get_by_name(timer_node_name.as_slice()).unwrap();

  let pin = TokenString(pin_node_name);
  let timer = TokenString(timer_node_name);
  let name = TokenString(node.name.clone().unwrap());

  let typename = format!(
      "zinc::drivers::dht22::DHT22<'a, {}, {}>",
      timer_node.type_name().unwrap(),
      pin_node.type_name().unwrap());
  node.set_type_name(typename);

  let st = quote_stmt!(&*cx,
      let $name = zinc::drivers::dht22::DHT22::new(&$timer, &$pin);
  );
  builder.add_main_statement(st);
}

#[cfg(test)]
mod test {
  use builder::Builder;
  use test_helpers::{assert_equal_source, with_parsed, equal_to, equal_to_s};
  use hamcrest::{assert_that,is};

  #[test]
  fn builds_lpc17xx_pt() {
    with_parsed("
      timer@timer;
      pin@pin;
      dht@dht22 {
        pin = &pin;
        timer = &timer;
      }", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      pt.get_by_name("timer").unwrap().set_type_name("T".to_str());
      pt.get_by_name("pin").unwrap().set_type_name("P".to_str());
      super::mutate_pin(&mut builder, cx, pt.get_by_name("dht").unwrap());
      super::build_dht22(&mut builder, cx, pt.get_by_name("dht").unwrap());
      assert_that(unsafe{*failed}, is(equal_to(false)));
      assert_that(builder.main_stmts.len(), is(equal_to(1u)));

      assert_equal_source(builder.main_stmts.get(0),
          "let dht = zinc::drivers::dht22::DHT22::new(&timer, &pin);");

      let pin_node = pt.get_by_name("pin").unwrap();
      assert_that(pin_node.get_string_attr("direction").unwrap(),
          is(equal_to_s("out")));

      assert_that(pt.get_by_name("dht").unwrap().type_name().unwrap(),
          is(equal_to_s("zinc::drivers::dht22::DHT22<'a, T, P>")));
    });
  }
}
<|endoftext|>


<commit_before>// error-pattern: Wrong number of type arguments

tag quux<T> { }

fn foo(c: quux) { assert (false); }

fn main() { fail; }
<commit_msg>test: Don't test that tags with zero variants are supported<commit_after>// error-pattern: Wrong number of type arguments

tag quux<T> { bar }

fn foo(c: quux) { assert (false); }

fn main() { fail; }
<|endoftext|>