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

use dom::bindings::codegen::Bindings::WorkerBinding;
use dom::bindings::error::{Fallible, Syntax};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{Temporary, RootCollection};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use dom::eventtarget::{EventTarget, WorkerTypeId};
use script_task::StackRootTLS;

use servo_net::resource_task::load_whole_resource;
use servo_util::str::DOMString;
use servo_util::url::try_parse_url;

use native;
use rustrt::task::TaskOpts;

#[deriving(Encodable)]
pub struct Worker {
    eventtarget: EventTarget,
}

impl Worker {
    pub fn new_inherited() -> Worker {
        Worker {
            eventtarget: EventTarget::new_inherited(WorkerTypeId),
        }
    }

    pub fn new(global: &GlobalRef) -> Temporary<Worker> {
        reflect_dom_object(box Worker::new_inherited(),
                           global,
                           WorkerBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef, scriptURL: DOMString) -> Fallible<Temporary<Worker>> {
        // Step 2-4.
        let worker_url = match try_parse_url(scriptURL.as_slice(), Some(global.get_url())) {
            Ok(url) => url,
            Err(_) => return Err(Syntax),
        };

        let resource_task = global.page().resource_task.deref().clone();

        let mut task_opts = TaskOpts::new();
        task_opts.name = Some(format!("Web Worker at {}", worker_url).into_maybe_owned());
        native::task::spawn_opts(task_opts, proc() {
            let roots = RootCollection::new();
            let _stack_roots_tls = StackRootTLS::new(&roots);

            let (filename, source) = match load_whole_resource(&resource_task, worker_url.clone()) {
                Err(_) => {
                    println!("error loading script {}", worker_url);
                    return;
                }
                Ok((metadata, bytes)) => {
                    (metadata.final_url, String::from_utf8(bytes).unwrap())
                }
            };

            let global = DedicatedWorkerGlobalScope::init().root();
            match global.get_rust_cx().evaluate_script(
                global.reflector().get_jsobject(), source, filename.to_str(), 1) {
                Ok(_) => (),
                Err(_) => println!("evaluate_script failed")
            }
        });

        Ok(Worker::new(global))
    }
}

pub trait WorkerMethods {
}

impl Reflectable for Worker {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }
}
<commit_msg>Add a spec link for the Worker constructor.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::WorkerBinding;
use dom::bindings::error::{Fallible, Syntax};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{Temporary, RootCollection};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use dom::eventtarget::{EventTarget, WorkerTypeId};
use script_task::StackRootTLS;

use servo_net::resource_task::load_whole_resource;
use servo_util::str::DOMString;
use servo_util::url::try_parse_url;

use native;
use rustrt::task::TaskOpts;

#[deriving(Encodable)]
pub struct Worker {
    eventtarget: EventTarget,
}

impl Worker {
    pub fn new_inherited() -> Worker {
        Worker {
            eventtarget: EventTarget::new_inherited(WorkerTypeId),
        }
    }

    pub fn new(global: &GlobalRef) -> Temporary<Worker> {
        reflect_dom_object(box Worker::new_inherited(),
                           global,
                           WorkerBinding::Wrap)
    }

    // http://www.whatwg.org/html/#dom-worker
    pub fn Constructor(global: &GlobalRef, scriptURL: DOMString) -> Fallible<Temporary<Worker>> {
        // Step 2-4.
        let worker_url = match try_parse_url(scriptURL.as_slice(), Some(global.get_url())) {
            Ok(url) => url,
            Err(_) => return Err(Syntax),
        };

        let resource_task = global.page().resource_task.deref().clone();

        let mut task_opts = TaskOpts::new();
        task_opts.name = Some(format!("Web Worker at {}", worker_url).into_maybe_owned());
        native::task::spawn_opts(task_opts, proc() {
            let roots = RootCollection::new();
            let _stack_roots_tls = StackRootTLS::new(&roots);

            let (filename, source) = match load_whole_resource(&resource_task, worker_url.clone()) {
                Err(_) => {
                    println!("error loading script {}", worker_url);
                    return;
                }
                Ok((metadata, bytes)) => {
                    (metadata.final_url, String::from_utf8(bytes).unwrap())
                }
            };

            let global = DedicatedWorkerGlobalScope::init().root();
            match global.get_rust_cx().evaluate_script(
                global.reflector().get_jsobject(), source, filename.to_str(), 1) {
                Ok(_) => (),
                Err(_) => println!("evaluate_script failed")
            }
        });

        Ok(Worker::new(global))
    }
}

pub trait WorkerMethods {
}

impl Reflectable for Worker {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate env_logger;
#[macro_use]
extern crate log as irrelevant_log;
extern crate juniper;
extern crate juniper_warp;
extern crate warp;

use juniper::tests::model::Database;
use juniper::{EmptyMutation, RootNode};
use warp::{http::Response, log, Filter};

type Schema = RootNode<'static, Database, EmptyMutation<Database>>;

fn schema() -> Schema {
    Schema::new(Database::new(), EmptyMutation::<Database>::new())
}

fn main() {
    ::std::env::set_var("RUST_LOG", "warp_server");
    env_logger::init();

    let log = log("warp_server");

    let homepage = warp::index().map(|| {
        Response::builder()
            .header("content-type", "text/html")
            .body(format!(
                "
juniper_warp

visit /graphiql"
            ))
    });

    info!("Listening on 127.0.0.1:8080");

    let state = warp::any().map(move || Database::new());
    let graphql_filter = juniper_warp::make_graphql_filter(schema(), state.boxed());

    warp::serve(
        warp::get2()
            .and(warp::path("graphiql"))
            .and(juniper_warp::graphiql_handler("/graphql"))
            .or(homepage)
            .or(warp::path("graphql").and(graphql_filter))
            .with(log),
    ).run(([127, 0, 0, 1], 8080));
}
<commit_msg>Fix build<commit_after>#![deny(warnings)]

extern crate env_logger;
#[macro_use]
extern crate log as irrelevant_log;
extern crate juniper;
extern crate juniper_warp;
extern crate warp;

use juniper::tests::model::Database;
use juniper::{EmptyMutation, RootNode};
use warp::{http::Response, log, Filter};

type Schema = RootNode<'static, Database, EmptyMutation<Database>>;

fn schema() -> Schema {
    Schema::new(Database::new(), EmptyMutation::<Database>::new())
}

fn main() {
    ::std::env::set_var("RUST_LOG", "warp_server");
    env_logger::init();

    let log = log("warp_server");

    let homepage = warp::index().map(|| {
        Response::builder()
            .header("content-type", "text/html")
            .body(format!(
                "
juniper_warp

visit /graphiql"
            ))
    });

    info!("Listening on 127.0.0.1:8080");

    let state = warp::any().map(move || Database::new());
    let graphql_filter = juniper_warp::make_graphql_filter(schema(), state.boxed());

    warp::serve(
        warp::get2()
            .and(warp::path("graphiql"))
            .and(juniper_warp::graphiql_filter("/graphql"))
            .or(homepage)
            .or(warp::path("graphql").and(graphql_filter))
            .with(log),
    ).run(([127, 0, 0, 1], 8080));
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![allow(clippy::useless_attribute)] //issue #2910

#[macro_use]
extern crate serde_derive;

/// Test that we do not lint for unused underscores in a `MacroAttribute`
/// expansion
#[deny(clippy::used_underscore_binding)]
#[derive(Deserialize)]
struct MacroAttributesTest {
    _foo: u32,
}

#[test]
fn macro_attributes_test() {
    let _ = MacroAttributesTest { _foo: 0 };
}

fn main() {}
<commit_msg>Auto merge of #3629 - matthiaskrgr:crash_workaround, r=phansch<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![allow(clippy::useless_attribute)] //issue #2910
#![allow(clippy::random_state)] // issue #3628

#[macro_use]
extern crate serde_derive;

/// Test that we do not lint for unused underscores in a `MacroAttribute`
/// expansion
#[deny(clippy::used_underscore_binding)]
#[derive(Deserialize)]
struct MacroAttributesTest {
    _foo: u32,
}

#[test]
fn macro_attributes_test() {
    let _ = MacroAttributesTest { _foo: 0 };
}

fn main() {}
<|endoftext|>


<commit_before>
import front::ast;
import front::codemap;
import util::common::span;
import util::common::ty_mach;
import std::uint;
import std::term;
import std::io;
import std::map;
import std::option;
import std::option::some;
import std::option::none;

tag os { os_win32; os_macos; os_linux; }

tag arch { arch_x86; arch_x64; arch_arm; }

type config =
    rec(os os,
        arch arch,
        ty_mach int_type,
        ty_mach uint_type,
        ty_mach float_type);

type options =
    rec(bool shared,
        uint optimize,
        bool debuginfo,
        bool verify,
        bool run_typestate,
        bool save_temps,
        bool stats,
        bool time_passes,
        bool time_llvm_passes,
        back::link::output_type output_type,
        vec[str] library_search_paths,
        str sysroot);

type crate_metadata = rec(str name, vec[u8] data);

fn span_to_str(span sp, codemap::codemap cm) -> str {
    auto lo = codemap::lookup_pos(cm, sp.lo);
    auto hi = codemap::lookup_pos(cm, sp.hi);
    ret #fmt("%s:%u:%u:%u:%u", lo.filename, lo.line, lo.col, hi.line, hi.col);
}

fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color,
                   codemap::codemap cm) {
    auto ss = "<input>:0:0:0:0";
    alt (sp) {
        case (some(?ssp)) { ss = span_to_str(ssp, cm); }
        case (none) { }
    }
    io::stdout().write_str(ss + ": ");
    if (term::color_supported()) {
        term::fg(io::stdout().get_buf_writer(), color);
    }
    io::stdout().write_str(#fmt("%s:", kind));
    if (term::color_supported()) {
        term::reset(io::stdout().get_buf_writer());
    }
    io::stdout().write_str(#fmt(" %s\n", msg));
}

obj session(ast::crate_num cnum,
            @config targ_cfg,
            @options opts,
            map::hashmap[int, crate_metadata] crates,
            mutable vec[str] used_crate_files,
            mutable vec[str] used_libraries,
            codemap::codemap cm,
            mutable uint err_count) {
    fn get_targ_cfg() -> @config { ret targ_cfg; }
    fn get_opts() -> @options { ret opts; }
    fn get_targ_crate_num() -> ast::crate_num { ret cnum; }
    fn span_fatal(span sp, str msg) -> ! {
        // FIXME: Use constants, but rustboot doesn't know how to export them.

        emit_diagnostic(some(sp), msg, "error", 9u8, cm);
        fail;
    }
    fn fatal(str msg) -> ! {
        emit_diagnostic(none[span], msg, "error", 9u8, cm);
        fail;
    }
    fn span_err(span sp, str msg) {
        emit_diagnostic(some(sp), msg, "error", 9u8, cm);
        err_count += 1u;
    }
    fn err(str msg) {
        emit_diagnostic(none, msg, "error", 9u8, cm);
        err_count += 1u;
    }
    fn abort_if_errors() {
        if (err_count > 0u) {
            self.fatal("aborting due to previous errors");
        }
    }
    fn span_warn(span sp, str msg) {
        // FIXME: Use constants, but rustboot doesn't know how to export them.

        emit_diagnostic(some(sp), msg, "warning", 11u8, cm);
    }
    fn warn(str msg) {
        emit_diagnostic(none[span], msg, "warning", 11u8, cm);
    }
    fn span_note(span sp, str msg) {
        // FIXME: Use constants, but rustboot doesn't know how to export them.

        emit_diagnostic(some(sp), msg, "note", 10u8, cm);
    }
    fn span_bug(span sp, str msg) -> ! {
        self.span_fatal(sp, #fmt("internal compiler error %s", msg));
    }
    fn bug(str msg) -> ! {
        self.fatal(#fmt("internal compiler error %s", msg));
    }
    fn span_unimpl(span sp, str msg) -> ! {
        self.span_bug(sp, "unimplemented " + msg);
    }
    fn unimpl(str msg) -> ! { self.bug("unimplemented " + msg); }
    fn get_external_crate(int num) -> crate_metadata { ret crates.get(num); }
    fn set_external_crate(int num, &crate_metadata metadata) {
        crates.insert(num, metadata);
    }
    fn has_external_crate(int num) -> bool { ret crates.contains_key(num); }
    fn add_used_library(&str lib) {
        if (lib == "") {
            ret;
        }
        // A program has a small number of libraries, so a vector is probably
        // a good data structure in here.
        for (str l in used_libraries) {
            if (l == lib) {
                ret;
            }
        }
        used_libraries += [lib];
    }
    fn get_used_libraries() -> vec[str] {
       ret used_libraries;
    }
    fn add_used_crate_file(&str lib) {
        // A program has a small number of crates, so a vector is probably
        // a good data structure in here.
        for (str l in used_crate_files) {
            if (l == lib) {
                ret;
            }
        }
        used_crate_files += [lib];
    }
    fn get_used_crate_files() -> vec[str] {
       ret used_crate_files;
    }
    fn get_codemap() -> codemap::codemap { ret cm; }
    fn lookup_pos(uint pos) -> codemap::loc {
        ret codemap::lookup_pos(cm, pos);
    }
    fn span_str(span sp) -> str { ret span_to_str(sp, self.get_codemap()); }
}
// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Add session.note method<commit_after>
import front::ast;
import front::codemap;
import util::common::span;
import util::common::ty_mach;
import std::uint;
import std::term;
import std::io;
import std::map;
import std::option;
import std::option::some;
import std::option::none;

tag os { os_win32; os_macos; os_linux; }

tag arch { arch_x86; arch_x64; arch_arm; }

type config =
    rec(os os,
        arch arch,
        ty_mach int_type,
        ty_mach uint_type,
        ty_mach float_type);

type options =
    rec(bool shared,
        uint optimize,
        bool debuginfo,
        bool verify,
        bool run_typestate,
        bool save_temps,
        bool stats,
        bool time_passes,
        bool time_llvm_passes,
        back::link::output_type output_type,
        vec[str] library_search_paths,
        str sysroot);

type crate_metadata = rec(str name, vec[u8] data);

fn span_to_str(span sp, codemap::codemap cm) -> str {
    auto lo = codemap::lookup_pos(cm, sp.lo);
    auto hi = codemap::lookup_pos(cm, sp.hi);
    ret #fmt("%s:%u:%u:%u:%u", lo.filename, lo.line, lo.col, hi.line, hi.col);
}

fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color,
                   codemap::codemap cm) {
    auto ss = "<input>:0:0:0:0";
    alt (sp) {
        case (some(?ssp)) { ss = span_to_str(ssp, cm); }
        case (none) { }
    }
    io::stdout().write_str(ss + ": ");
    if (term::color_supported()) {
        term::fg(io::stdout().get_buf_writer(), color);
    }
    io::stdout().write_str(#fmt("%s:", kind));
    if (term::color_supported()) {
        term::reset(io::stdout().get_buf_writer());
    }
    io::stdout().write_str(#fmt(" %s\n", msg));
}

obj session(ast::crate_num cnum,
            @config targ_cfg,
            @options opts,
            map::hashmap[int, crate_metadata] crates,
            mutable vec[str] used_crate_files,
            mutable vec[str] used_libraries,
            codemap::codemap cm,
            mutable uint err_count) {
    fn get_targ_cfg() -> @config { ret targ_cfg; }
    fn get_opts() -> @options { ret opts; }
    fn get_targ_crate_num() -> ast::crate_num { ret cnum; }
    fn span_fatal(span sp, str msg) -> ! {
        // FIXME: Use constants, but rustboot doesn't know how to export them.

        emit_diagnostic(some(sp), msg, "error", 9u8, cm);
        fail;
    }
    fn fatal(str msg) -> ! {
        emit_diagnostic(none[span], msg, "error", 9u8, cm);
        fail;
    }
    fn span_err(span sp, str msg) {
        emit_diagnostic(some(sp), msg, "error", 9u8, cm);
        err_count += 1u;
    }
    fn err(str msg) {
        emit_diagnostic(none, msg, "error", 9u8, cm);
        err_count += 1u;
    }
    fn abort_if_errors() {
        if (err_count > 0u) {
            self.fatal("aborting due to previous errors");
        }
    }
    fn span_warn(span sp, str msg) {
        // FIXME: Use constants, but rustboot doesn't know how to export them.

        emit_diagnostic(some(sp), msg, "warning", 11u8, cm);
    }
    fn warn(str msg) {
        emit_diagnostic(none[span], msg, "warning", 11u8, cm);
    }
    fn span_note(span sp, str msg) {
        // FIXME: Use constants, but rustboot doesn't know how to export them.

        emit_diagnostic(some(sp), msg, "note", 10u8, cm);
    }
    fn note(str msg) {
        emit_diagnostic(none, msg, "note", 10u8, cm);
    }
    fn span_bug(span sp, str msg) -> ! {
        self.span_fatal(sp, #fmt("internal compiler error %s", msg));
    }
    fn bug(str msg) -> ! {
        self.fatal(#fmt("internal compiler error %s", msg));
    }
    fn span_unimpl(span sp, str msg) -> ! {
        self.span_bug(sp, "unimplemented " + msg);
    }
    fn unimpl(str msg) -> ! { self.bug("unimplemented " + msg); }
    fn get_external_crate(int num) -> crate_metadata { ret crates.get(num); }
    fn set_external_crate(int num, &crate_metadata metadata) {
        crates.insert(num, metadata);
    }
    fn has_external_crate(int num) -> bool { ret crates.contains_key(num); }
    fn add_used_library(&str lib) {
        if (lib == "") {
            ret;
        }
        // A program has a small number of libraries, so a vector is probably
        // a good data structure in here.
        for (str l in used_libraries) {
            if (l == lib) {
                ret;
            }
        }
        used_libraries += [lib];
    }
    fn get_used_libraries() -> vec[str] {
       ret used_libraries;
    }
    fn add_used_crate_file(&str lib) {
        // A program has a small number of crates, so a vector is probably
        // a good data structure in here.
        for (str l in used_crate_files) {
            if (l == lib) {
                ret;
            }
        }
        used_crate_files += [lib];
    }
    fn get_used_crate_files() -> vec[str] {
       ret used_crate_files;
    }
    fn get_codemap() -> codemap::codemap { ret cm; }
    fn lookup_pos(uint pos) -> codemap::loc {
        ret codemap::lookup_pos(cm, pos);
    }
    fn span_str(span sp) -> str { ret span_to_str(sp, self.get_codemap()); }
}
// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::collections::Bitv;

/// Sort LMS suffixes (step 1).
fn get_lms_pos(text: &[usize], pos_types: Bitv) {
    let lms: Vec<bool> = pos_types.iter().enumerate().scan(false, |prev, (i, is_s)| {
        let prev_is_l = !*prev;
        *prev = is_s;
        Some(prev_is_l && is_s)
    }).collect();

    // determine LMS positions
    let lms_init_pos: Vec<usize> = lms.iter().enumerate().filter_map(|(i, &is_lms)| {
        if is_lms { Some(i) } else { None }
    }).collect();

    // sort LMS substrings
    let lms_substring_pos = get_pos(text, pos_types, &lms_init_pos[]);

    let mut i = 0;
    for r in 0..lms_substring_pos.len() {

    }
}

/// Sort other suffixes using sorted LMS suffixes (step 2).
fn get_pos(text: &[usize], pos_types: Bitv, lms_pos: &[usize]) -> Vec<usize> {
    let n = text.len();
    let mut pos = Vec::with_capacity(text.len());

    let mut bucket_start = get_bucket_start(text);
    let mut bucket_end = bucket_start.clone()[1..].to_vec();
    bucket_end.push(text.len());
    let mut bucket_end_lms = bucket_end.clone();

    // init all positions as unknown
    for _ in text.iter() {
        pos.push(n);
    }

    // insert LMS positions to the end of their buckets
    for &p in lms_pos.iter().rev() {
        let c = text[p];
        pos[bucket_end_lms[c]] = p;
        bucket_end_lms[c] -= 1;
    }

    // insert L-positions into buckets
    for r in 0..pos.len() {
        let p = pos[r];
        if p == n {
            continue;
        }
        let prev = p - 1;
        if !pos_types.get(prev).unwrap() {
            // L-position, insert into bucket
            let c = text[prev];
            pos[bucket_start[c]] = prev;
            bucket_start[c] += 1;
        }
    }

    for r in (0..pos.len()).rev() {
        let prev = pos[r] - 1;
        if pos_types.get(prev).unwrap() {
            let c = text[prev];
            pos[bucket_end[c]] = prev;
            bucket_end[c] -= 1;
        }
    }

    pos
}

fn get_bucket_start(text: &[usize]) -> Vec<usize> {
    let alphabet_size = *text.iter().max().unwrap();
    let mut bucket_sizes = Vec::with_capacity(alphabet_size);

    for _ in (0..alphabet_size) {
        bucket_sizes.push(0);
    }

    for &c in text.iter() {
        bucket_sizes[c as usize] += 1;
    }

    let mut bucket_start = Vec::with_capacity(alphabet_size as usize);
    let mut sum = 0;
    for &size in bucket_sizes.iter() {
        bucket_start.push(sum);
        sum += size;
    }

    bucket_start
}

/// Calculate the text position type.
/// S-type marks suffixes being lexicographically smaller than their successor,
/// L-type marks those being larger.
/// This function returns a Bitv, with 1-bits denoting S-type
/// and 0-bits denoting L-type.
///
/// # Arguments
///
/// * `text` - the text, ending with a sentinel '$'.
///
/// # Example
///
/// ```rust
/// use std::collections::Bitv;
/// use bio::data_structures::suffix_array::get_pos_type;
/// let text = b"GCCTTAACATTATTACGCCTA$";
/// let pos_type = get_pos_type(text);
/// let mut test = Bitv::from_bytes(&[0b01100110, 0b10010011,  0b01100100]);
/// test.truncate(text.len());
/// assert_eq!(pos_type, test);
/// ```
pub fn get_pos_types(text: &[usize]) -> Bitv {
    let n = text.len();
    let mut pos_types = Bitv::from_elem(n, false);
    pos_types.set(n - 1, true);
    for p in (0..n-1).rev() {
        if text[p] == text[p + 1] {
            // if the characters are equal, the next position determines
            // the lexicographical order
            let v = pos_types.get(p + 1).unwrap();
            pos_types.set(p, v);
        }
        else {
            pos_types.set(p, text[p] < text[p + 1]);
        }
    }

    pos_types
}
<commit_msg>Rewriting suffix array with reusable arrays.<commit_after>use std::collections::{Bitv, VecMap};
use std::collections::bitv::Iter;

struct SAIS {
    pos: Vec<usize>,
    pos_types: Bitv,
    lms_pos: Vec<usize>,
    bucket_sizes: VecMap<usize>,
    bucket_start: Vec<usize>,
    bucket_end: Vec<usize>
}

impl SAIS {
    fn new(n: usize) -> Self {
        SAIS {
            pos: Vec::with_capacity(n),
            pos_types: Bitv::with_capacity(n),
            lms_pos: Vec::with_capacity(n),
            bucket_sizes: VecMap::new(),
            bucket_start: Vec::with_capacity(n),
            bucket_end: Vec::with_capacity(n)
        }
    }

    fn init_pos_types(&mut self, text: &[usize]) {
        let n = text.len();
        self.pos_types.clear();

        for _ in 0..n-1 {
            self.pos_types.push(false);
        }
        self.pos_types.push(true);

        for p in (0..n-1).rev() {
            if text[p] == text[p + 1] {
                // if the characters are equal, the next position determines
                // the lexicographical order
                let v = self.pos_types.get(p + 1).unwrap();
                self.pos_types.set(p, v);
            }
            else {
                self.pos_types.set(p, text[p] < text[p + 1]);
            }
        }
    }

    fn init_bucket_start(&mut self, text: &[usize]) {
        self.bucket_sizes.clear();
        self.bucket_start.clear();

        for &c in text.iter() {
            if !self.bucket_sizes.contains_key(&c) {
                self.bucket_sizes.insert(c, 0);
            }
            *(self.bucket_sizes.get_mut(&c).unwrap()) += 1;
        }

        let mut sum = 0;
        for &size in self.bucket_sizes.values() {
            self.bucket_start.push(sum);
            sum += size;
        }
    }

    fn init_bucket_end(&mut self, text: &[usize]) {
        self.bucket_end.clear();
        for &r in self.bucket_start[1..].iter() {
            self.bucket_end.push(r);
        }
        self.bucket_end.push(text.len());
    }

    fn is_s_pos(&self, r: usize) -> bool {
        self.pos_types.get(r).unwrap()
    }

    fn is_l_pos(&self, r: usize) -> bool {
        !self.pos_types.get(r).unwrap()
    }

    fn is_lms_pos(&self, r: usize) -> bool {
        self.is_s_pos(r) && self.is_l_pos(r)
    }

    /// Step 1 of the SAIS algorithm.
    fn calc_lms_pos(&mut self, text: &[usize]) {
        let n = text.len();

        // collect LMS positions
        self.lms_pos.clear();
        for r in (0..n) {
            if self.is_lms_pos(r) {
                self.lms_pos.push(r);
            }
        }

        // sort LMS substrings
        self.calc_pos(text);

    }

    /// Step 2 of the SAIS algorithm.
    fn calc_pos(&mut self, text: &[usize]) {
        let n = text.len();
        self.pos.clear();

        self.init_bucket_start(text);
        self.init_bucket_end(text);

        // init all positions as unknown (n-1 is max position)
        for _ in text.iter() {
            self.pos.push(n);
        }

        // insert LMS positions to the end of their buckets
        for &p in self.lms_pos.iter().rev() {
            let c = text[p];
            self.pos[self.bucket_end[c]] = p;
            self.bucket_end[c] -= 1;
        }

        // reset bucket ends
        self.init_bucket_end(text);

        // insert L-positions into buckets
        for r in (0..n) {
            let p = self.pos[r];
            if p == n {
                continue;
            }
            let prev = p - 1;
            if self.is_l_pos(prev) {
                let c = text[prev];
                self.pos[self.bucket_start[c]] = prev;
                self.bucket_start[c] += 1;
            }
        }

        // insert S-positions into buckets
        for r in (0..n).rev() {
            let prev = self.pos[r] - 1;
            if self.is_s_pos(prev) {
                let c = text[prev];
                self.pos[self.bucket_end[c]] = prev;
                self.bucket_end[c] -= 1;
            }
        }
    }
}

/// DEPRECATED: Calculate the text position type.
/// S-type marks suffixes being lexicographically smaller than their successor,
/// L-type marks those being larger.
/// This function returns a Bitv, with 1-bits denoting S-type
/// and 0-bits denoting L-type.
///
/// # Arguments
///
/// * `text` - the text, ending with a sentinel '$'.
///
/// # Example
///
/// ```rust
/// use std::collections::Bitv;
/// use bio::data_structures::suffix_array::get_pos_type;
/// let text = b"GCCTTAACATTATTACGCCTA$";
/// let pos_type = get_pos_type(text);
/// let mut test = Bitv::from_bytes(&[0b01100110, 0b10010011,  0b01100100]);
/// test.truncate(text.len());
/// assert_eq!(pos_type, test);
/// ```
pub fn get_pos_types(text: &[usize]) -> Bitv {
    let n = text.len();
    let mut pos_types = Bitv::from_elem(n, false);
    pos_types.set(n - 1, true);
    for p in (0..n-1).rev() {
        if text[p] == text[p + 1] {
            // if the characters are equal, the next position determines
            // the lexicographical order
            let v = pos_types.get(p + 1).unwrap();
            pos_types.set(p, v);
        }
        else {
            pos_types.set(p, text[p] < text[p + 1]);
        }
    }

    pos_types
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::{Read, Write, BufReader, BufRead};
use std::os::unix::ffi::OsStrExt;

use regex::Regex;
use quire::validate as V;

use super::super::context::Context;
use super::super::packages;
use super::generic::{capture_command, run_command_at_env};
use builder::distrib::Distribution;
use builder::commands::generic::{command, run};
use process_util::capture_stdout;
use build_step::{BuildStep, VersionError, StepError, Digest, Config, Guard};

const DEFAULT_GEM_EXE: &'static str = "/usr/bin/gem";
const BIN_DIR: &'static str = "/usr/local/bin";
const GEM_VERSION_WITH_NO_DOCUMENT_OPT: f32 = 2.0;
const VALID_TRUST_POLICIES: [&'static str; 3] = ["LowSecurity", "MediumSecurity", "HighSecurity"];

#[derive(Debug)]
pub struct GemInstall(Vec<String>);
tuple_struct_decode!(GemInstall);

impl GemInstall {
    pub fn config() -> V::Sequence<'static> {
        V::Sequence::new(V::Scalar::new())
    }
}

#[derive(RustcDecodable, Debug, Clone)]
pub struct GemConfig {
    pub install_ruby: bool,
    pub gem_exe: Option<String>,
    pub update_gem: bool,
}

impl GemConfig {
    pub fn config() -> V::Structure<'static> {
        V::Structure::new()
        .member("install_ruby", V::Scalar::new().default(true))
        .member("gem_exe", V::Scalar::new().optional())
        .member("update_gem", V::Scalar::new().default(true))
    }
}

#[derive(RustcDecodable, Debug)]
pub struct GemBundle {
    pub gemfile: PathBuf,
    pub without: Vec<String>,
    pub trust_policy: Option<String>,
}

impl GemBundle {
    pub fn config() -> V::Structure<'static> {
        V::Structure::new()
        .member("gemfile", V::Scalar::new().default("Gemfile"))
        .member("without", V::Sequence::new(V::Scalar::new()))
        .member("trust_policy", V::Scalar::new().optional())
    }
}

impl Default for GemConfig {
    fn default() -> Self {
        GemConfig {
            install_ruby: true,
            gem_exe: None,
            update_gem: true,
        }
    }
}

fn no_doc_args(ctx: &mut Context) -> Result<Vec<&'static str>, String> {
    if ctx.gem_settings.update_gem {
        Ok(vec!("--no-document"))
    } else {
        let version = try!(gem_version(ctx));
        if version < GEM_VERSION_WITH_NO_DOCUMENT_OPT {
            Ok(vec!("--no-rdoc", "--no-ri"))
        } else {
            Ok(vec!("--no-document"))
        }
    }
}

fn gem_version(ctx: &mut Context) -> Result<f32, String> {
    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let args = [
        gem_exe,
        "--version".to_owned(),
    ];

    let gem_ver = try!(capture_command(ctx, &args, &[])
        .and_then(|x| String::from_utf8(x)
            .map_err(|e| format!("Error parsing gem version: {}", e)))
        .map_err(|e| format!("Error getting gem version: {}", e)));

    let re = Regex::new(r#"^(\d+?\.\d+?)\."#).expect("Invalid regex");
    let version = try!(re.captures(&gem_ver)
        .and_then(|cap| cap.at(1))
        .ok_or("Gem version was not found".to_owned()));

    version.parse::<f32>()
        .map_err(|e| format!("Erro parsing gem version: {}", e))
}

fn gem_cache_dir(ctx: &mut Context) -> Result<PathBuf, String> {
    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let args = [
        gem_exe,
        "env".to_owned(),
        "gemdir".to_owned(),
    ];

    let gem_dir = try!(capture_command(ctx, &args, &[])
        .and_then(|x| String::from_utf8(x)
            .map_err(|e| format!("Error getting gem dir: {}", e))));

    Ok(Path::new(gem_dir.trim()).join("cache"))
}

fn requires_git(gemfile: &Path) -> Result<bool, String> {
    let gemfile = Path::new("/work").join(gemfile);

    let re = Regex::new(
        r#"(git .*? do)|(:(git|github|gist|bitbucket) =>)|(git_source\(.*?\))"#
    ).expect("Invalid regex");

    let gemfile_data = {
        let mut buf = String::new();
        try!(File::open(&gemfile)
            .and_then(|mut f| f.read_to_string(&mut buf))
            .map_err(|e| format!("Error reading Gemfile ({:?}): {}", &gemfile, e)));

        buf
    };

    Ok(re.is_match(&gemfile_data))
}

fn scan_features(settings: &GemConfig, info: Option<&GemBundle>)
    -> Result<Vec<packages::Package>, String>
{
    let mut res = vec!();
    res.push(packages::BuildEssential);

    if settings.install_ruby {
        res.push(packages::Ruby);
        res.push(packages::RubyDev);
    }

    res.push(packages::Bundler);

    if let Some(info) = info {
        let git_required = try!(requires_git(&info.gemfile));
        if git_required {
            res.push(packages::Git);
        }
    }

    Ok(res)
}

pub fn install(distro: &mut Box<Distribution>,
    ctx: &mut Context, pkgs: &Vec<String>)
    -> Result<(), String>
{
    let features = try!(scan_features(&ctx.gem_settings, None));
    try!(packages::ensure_packages(distro, ctx, &features));

    try!(configure(ctx));

    if pkgs.len() == 0 {
        return Ok(());
    }

    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let mut cmd = try!(command(ctx, &gem_exe));
    cmd.arg("install");
    cmd.args(&["--bindir", BIN_DIR]);

    let no_doc = try!(no_doc_args(ctx));
    cmd.args(&no_doc);

    cmd.args(pkgs);
    try!(run(cmd));
    Ok(())
}

pub fn bundle(distro: &mut Box<Distribution>,
    ctx: &mut Context, info: &GemBundle)
    -> Result<(), StepError>
{
    let features = try!(scan_features(&ctx.gem_settings, Some(info)));
    try!(packages::ensure_packages(distro, ctx, &features));

    try!(configure(ctx));

    let mut cmd = try!(command(ctx, "bundle"));
    cmd.args(&["install", "--system", "--binstubs", BIN_DIR]);

    cmd.arg("--gemfile");
    cmd.arg(&info.gemfile);

    if !info.without.is_empty() {
        cmd.arg("--without");
        cmd.args(&info.without);
    }

    if let Some(ref trust_policy) = info.trust_policy {
        if !VALID_TRUST_POLICIES.contains(&trust_policy.as_ref()) {
            return return Err(From::from(format!(
                "Value of 'GemBundle.trust_policy' must be \
                    '{}', '{}' or '{}', '{}' given",
                VALID_TRUST_POLICIES[0],
                VALID_TRUST_POLICIES[1],
                VALID_TRUST_POLICIES[2],
                trust_policy
            )))
        }
        cmd.arg("--trust-policy");
        cmd.arg(trust_policy);
    }

    run(cmd)
}

pub fn configure(ctx: &mut Context) -> Result<(), String> {
    if ctx.gem_settings.gem_exe.is_none() &&
        ctx.gem_settings.update_gem
    {
        let mut args = vec!(
            DEFAULT_GEM_EXE.to_owned(),
            "update".to_owned(),
            "--system".to_owned(),
        );

        let version = try!(gem_version(ctx));
        if version < GEM_VERSION_WITH_NO_DOCUMENT_OPT {
            args.extend(vec!("--no-rdoc".to_owned(), "--no-ri".to_owned()));
        } else {
            args.push("--no-document".to_owned());
        }

        // Debian based distros doesn't allow updating gem unless this flag is set
        let env = [("REALLY_GEM_UPDATE_SYSTEM", "1")];
        try!(run_command_at_env(ctx, &args, Path::new("/work"), &env));
    }

    let gem_cache = try!(gem_cache_dir(ctx));
    try!(ctx.add_cache_dir(&gem_cache,
                           "gems-cache".to_string()));

    Ok(())
}

pub fn setup_bundler(ctx: &mut Context) -> Result<(), String> {
    try!(configure(ctx));

    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let mut cmd = try!(command(ctx, gem_exe));
    cmd.args(&["install", "bundler"]);

    let no_doc = try!(no_doc_args(ctx));
    cmd.args(&no_doc);

    try!(run(cmd));

    Ok(())
}

pub fn list(ctx: &mut Context) -> Result<(), StepError> {
    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let mut cmd = try!(command(ctx, gem_exe));
    cmd.arg("list");
    cmd.arg("--local");

    try!(capture_stdout(cmd)
        .and_then(|out| {
            File::create("/vagga/container/gems-list.txt")
            .and_then(|mut f| f.write_all(&out))
            .map_err(|e| format!("Error dumping gems package list: {}", e))
        }));
    Ok(())
}

impl BuildStep for GemInstall {
    fn hash(&self, _cfg: &Config, hash: &mut Digest)
        -> Result<(), VersionError>
    {
        hash.sequence("GemInstall", &self.0);
        Ok(())
    }
    fn build(&self, guard: &mut Guard, build: bool)
        -> Result<(), StepError>
    {
        if build {
            try!(install(&mut guard.distro, &mut guard.ctx, &self.0));
        }
        Ok(())
    }
    fn is_dependent_on(&self) -> Option<&str> {
        None
    }
}

impl BuildStep for GemConfig {
    fn hash(&self, _cfg: &Config, hash: &mut Digest)
        -> Result<(), VersionError>
    {
        hash.bool("install_ruby", self.install_ruby);
        hash.opt_field("gem_exe", &self.gem_exe);
        hash.bool("update_gem", self.update_gem);
        Ok(())
    }
    fn build(&self, guard: &mut Guard, _build: bool)
        -> Result<(), StepError>
    {
        guard.ctx.gem_settings = self.clone();
        Ok(())
    }
    fn is_dependent_on(&self) -> Option<&str> {
        None
    }
}

impl BuildStep for GemBundle {
    fn hash(&self, _cfg: &Config, hash: &mut Digest)
        -> Result<(), VersionError>
    {
        let path = Path::new("/work").join(&self.gemfile);

        hash.item(&self.gemfile.as_os_str().as_bytes());
        let gemlock = try!(path.parent()
            .map(|dir| dir.join("Gemfile.lock"))
            .ok_or("Gemfile should be under /work".to_owned()));
        if gemlock.exists() {
            let mut lockfile = try!(File::open(&path)
                .map_err(|e| VersionError::Io(e, gemlock.clone())));
            try!(hash.stream(&mut lockfile)
                .map_err(|e| VersionError::Io(e, gemlock.clone())));
        }

        let f = try!(File::open(&path)
            .map_err(|e| VersionError::Io(e, path.clone())));
        let reader = BufReader::new(f);

        for line in reader.lines() {
            let line = try!(line
                .map_err(|e| VersionError::Io(e, path.clone())));
            let line = line.trim();
            if line.is_empty() || line.starts_with("#") {
                continue
            }
            hash.item(line);
        }

        Ok(())
    }
    fn build(&self, guard: &mut Guard, build: bool)
        -> Result<(), StepError>
    {
        if build {
            try!(bundle(&mut guard.distro, &mut guard.ctx, self));
        }
        Ok(())
    }
    fn is_dependent_on(&self) -> Option<&str> {
        None
    }
}
<commit_msg>Install https certificates, fix ruby support<commit_after>use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::{Read, Write, BufReader, BufRead};
use std::os::unix::ffi::OsStrExt;

use regex::Regex;
use quire::validate as V;

use super::super::context::Context;
use super::super::packages;
use super::generic::{capture_command, run_command_at_env};
use builder::distrib::Distribution;
use builder::commands::generic::{command, run};
use process_util::capture_stdout;
use build_step::{BuildStep, VersionError, StepError, Digest, Config, Guard};

const DEFAULT_GEM_EXE: &'static str = "/usr/bin/gem";
const BIN_DIR: &'static str = "/usr/local/bin";
const GEM_VERSION_WITH_NO_DOCUMENT_OPT: f32 = 2.0;
const VALID_TRUST_POLICIES: [&'static str; 3] = ["LowSecurity", "MediumSecurity", "HighSecurity"];

#[derive(Debug)]
pub struct GemInstall(Vec<String>);
tuple_struct_decode!(GemInstall);

impl GemInstall {
    pub fn config() -> V::Sequence<'static> {
        V::Sequence::new(V::Scalar::new())
    }
}

#[derive(RustcDecodable, Debug, Clone)]
pub struct GemConfig {
    pub install_ruby: bool,
    pub gem_exe: Option<String>,
    pub update_gem: bool,
}

impl GemConfig {
    pub fn config() -> V::Structure<'static> {
        V::Structure::new()
        .member("install_ruby", V::Scalar::new().default(true))
        .member("gem_exe", V::Scalar::new().optional())
        .member("update_gem", V::Scalar::new().default(true))
    }
}

#[derive(RustcDecodable, Debug)]
pub struct GemBundle {
    pub gemfile: PathBuf,
    pub without: Vec<String>,
    pub trust_policy: Option<String>,
}

impl GemBundle {
    pub fn config() -> V::Structure<'static> {
        V::Structure::new()
        .member("gemfile", V::Scalar::new().default("Gemfile"))
        .member("without", V::Sequence::new(V::Scalar::new()))
        .member("trust_policy", V::Scalar::new().optional())
    }
}

impl Default for GemConfig {
    fn default() -> Self {
        GemConfig {
            install_ruby: true,
            gem_exe: None,
            update_gem: true,
        }
    }
}

fn no_doc_args(ctx: &mut Context) -> Result<Vec<&'static str>, String> {
    if ctx.gem_settings.update_gem {
        Ok(vec!("--no-document"))
    } else {
        let version = try!(gem_version(ctx));
        if version < GEM_VERSION_WITH_NO_DOCUMENT_OPT {
            Ok(vec!("--no-rdoc", "--no-ri"))
        } else {
            Ok(vec!("--no-document"))
        }
    }
}

fn gem_version(ctx: &mut Context) -> Result<f32, String> {
    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let args = [
        gem_exe,
        "--version".to_owned(),
    ];

    let gem_ver = try!(capture_command(ctx, &args, &[])
        .and_then(|x| String::from_utf8(x)
            .map_err(|e| format!("Error parsing gem version: {}", e)))
        .map_err(|e| format!("Error getting gem version: {}", e)));

    let re = Regex::new(r#"^(\d+?\.\d+?)\."#).expect("Invalid regex");
    let version = try!(re.captures(&gem_ver)
        .and_then(|cap| cap.at(1))
        .ok_or("Gem version was not found".to_owned()));

    version.parse::<f32>()
        .map_err(|e| format!("Erro parsing gem version: {}", e))
}

fn gem_cache_dir(ctx: &mut Context) -> Result<PathBuf, String> {
    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let args = [
        gem_exe,
        "env".to_owned(),
        "gemdir".to_owned(),
    ];

    let gem_dir = try!(capture_command(ctx, &args, &[])
        .and_then(|x| String::from_utf8(x)
            .map_err(|e| format!("Error getting gem dir: {}", e))));

    Ok(Path::new(gem_dir.trim()).join("cache"))
}

fn requires_git(gemfile: &Path) -> Result<bool, String> {
    let gemfile = Path::new("/work").join(gemfile);

    let re = Regex::new(
        r#"(git .*? do)|(:(git|github|gist|bitbucket) =>)|(git_source\(.*?\))"#
    ).expect("Invalid regex");

    let gemfile_data = {
        let mut buf = String::new();
        try!(File::open(&gemfile)
            .and_then(|mut f| f.read_to_string(&mut buf))
            .map_err(|e| format!("Error reading Gemfile ({:?}): {}", &gemfile, e)));

        buf
    };

    Ok(re.is_match(&gemfile_data))
}

fn scan_features(settings: &GemConfig, info: Option<&GemBundle>)
    -> Result<Vec<packages::Package>, String>
{
    let mut res = vec!();
    res.push(packages::BuildEssential);

    if settings.install_ruby {
        res.push(packages::Ruby);
        res.push(packages::RubyDev);
    }

    res.push(packages::Https);
    res.push(packages::Bundler);

    if let Some(info) = info {
        let git_required = try!(requires_git(&info.gemfile));
        if git_required {
            res.push(packages::Git);
        }
    }

    Ok(res)
}

pub fn install(distro: &mut Box<Distribution>,
    ctx: &mut Context, pkgs: &Vec<String>)
    -> Result<(), String>
{
    let features = try!(scan_features(&ctx.gem_settings, None));
    try!(packages::ensure_packages(distro, ctx, &features));

    try!(configure(ctx));

    if pkgs.len() == 0 {
        return Ok(());
    }

    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let mut cmd = try!(command(ctx, &gem_exe));
    cmd.arg("install");
    cmd.args(&["--bindir", BIN_DIR]);

    let no_doc = try!(no_doc_args(ctx));
    cmd.args(&no_doc);

    cmd.args(pkgs);
    try!(run(cmd));
    Ok(())
}

pub fn bundle(distro: &mut Box<Distribution>,
    ctx: &mut Context, info: &GemBundle)
    -> Result<(), StepError>
{
    let features = try!(scan_features(&ctx.gem_settings, Some(info)));
    try!(packages::ensure_packages(distro, ctx, &features));

    try!(configure(ctx));

    let mut cmd = try!(command(ctx, "bundle"));
    cmd.args(&["install", "--system", "--binstubs", BIN_DIR]);

    cmd.arg("--gemfile");
    cmd.arg(&info.gemfile);

    if !info.without.is_empty() {
        cmd.arg("--without");
        cmd.args(&info.without);
    }

    if let Some(ref trust_policy) = info.trust_policy {
        if !VALID_TRUST_POLICIES.contains(&trust_policy.as_ref()) {
            return return Err(From::from(format!(
                "Value of 'GemBundle.trust_policy' must be \
                    '{}', '{}' or '{}', '{}' given",
                VALID_TRUST_POLICIES[0],
                VALID_TRUST_POLICIES[1],
                VALID_TRUST_POLICIES[2],
                trust_policy
            )))
        }
        cmd.arg("--trust-policy");
        cmd.arg(trust_policy);
    }

    run(cmd)
}

pub fn configure(ctx: &mut Context) -> Result<(), String> {
    if ctx.gem_settings.gem_exe.is_none() &&
        ctx.gem_settings.update_gem
    {
        let mut args = vec!(
            DEFAULT_GEM_EXE.to_owned(),
            "update".to_owned(),
            "--system".to_owned(),
        );

        let version = try!(gem_version(ctx));
        if version < GEM_VERSION_WITH_NO_DOCUMENT_OPT {
            args.extend(vec!("--no-rdoc".to_owned(), "--no-ri".to_owned()));
        } else {
            args.push("--no-document".to_owned());
        }

        // Debian based distros doesn't allow updating gem unless this flag is set
        let env = [("REALLY_GEM_UPDATE_SYSTEM", "1")];
        try!(run_command_at_env(ctx, &args, Path::new("/work"), &env));
    }

    let gem_cache = try!(gem_cache_dir(ctx));
    try!(ctx.add_cache_dir(&gem_cache,
                           "gems-cache".to_string()));

    Ok(())
}

pub fn setup_bundler(ctx: &mut Context) -> Result<(), String> {
    try!(configure(ctx));

    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let mut cmd = try!(command(ctx, gem_exe));
    cmd.args(&["install", "bundler"]);

    let no_doc = try!(no_doc_args(ctx));
    cmd.args(&no_doc);

    try!(run(cmd));

    Ok(())
}

pub fn list(ctx: &mut Context) -> Result<(), StepError> {
    let gem_exe = ctx.gem_settings.gem_exe.clone()
        .unwrap_or(DEFAULT_GEM_EXE.to_owned());

    let mut cmd = try!(command(ctx, gem_exe));
    cmd.arg("list");
    cmd.arg("--local");

    try!(capture_stdout(cmd)
        .and_then(|out| {
            File::create("/vagga/container/gems-list.txt")
            .and_then(|mut f| f.write_all(&out))
            .map_err(|e| format!("Error dumping gems package list: {}", e))
        }));
    Ok(())
}

impl BuildStep for GemInstall {
    fn hash(&self, _cfg: &Config, hash: &mut Digest)
        -> Result<(), VersionError>
    {
        hash.sequence("GemInstall", &self.0);
        Ok(())
    }
    fn build(&self, guard: &mut Guard, build: bool)
        -> Result<(), StepError>
    {
        if build {
            try!(install(&mut guard.distro, &mut guard.ctx, &self.0));
        }
        Ok(())
    }
    fn is_dependent_on(&self) -> Option<&str> {
        None
    }
}

impl BuildStep for GemConfig {
    fn hash(&self, _cfg: &Config, hash: &mut Digest)
        -> Result<(), VersionError>
    {
        hash.bool("install_ruby", self.install_ruby);
        hash.opt_field("gem_exe", &self.gem_exe);
        hash.bool("update_gem", self.update_gem);
        Ok(())
    }
    fn build(&self, guard: &mut Guard, _build: bool)
        -> Result<(), StepError>
    {
        guard.ctx.gem_settings = self.clone();
        Ok(())
    }
    fn is_dependent_on(&self) -> Option<&str> {
        None
    }
}

impl BuildStep for GemBundle {
    fn hash(&self, _cfg: &Config, hash: &mut Digest)
        -> Result<(), VersionError>
    {
        let path = Path::new("/work").join(&self.gemfile);

        hash.item(&self.gemfile.as_os_str().as_bytes());
        let gemlock = try!(path.parent()
            .map(|dir| dir.join("Gemfile.lock"))
            .ok_or("Gemfile should be under /work".to_owned()));
        if gemlock.exists() {
            let mut lockfile = try!(File::open(&path)
                .map_err(|e| VersionError::Io(e, gemlock.clone())));
            try!(hash.stream(&mut lockfile)
                .map_err(|e| VersionError::Io(e, gemlock.clone())));
        }

        let f = try!(File::open(&path)
            .map_err(|e| VersionError::Io(e, path.clone())));
        let reader = BufReader::new(f);

        for line in reader.lines() {
            let line = try!(line
                .map_err(|e| VersionError::Io(e, path.clone())));
            let line = line.trim();
            if line.is_empty() || line.starts_with("#") {
                continue
            }
            hash.item(line);
        }

        Ok(())
    }
    fn build(&self, guard: &mut Guard, build: bool)
        -> Result<(), StepError>
    {
        if build {
            try!(bundle(&mut guard.distro, &mut guard.ctx, self));
        }
        Ok(())
    }
    fn is_dependent_on(&self) -> Option<&str> {
        None
    }
}
<|endoftext|>


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

//! Liveness analysis.

// FIXME: Make sure this analysis uses proper MIR semantics. Also find out what
//        the MIR semantics are.

use rustc::mir::*;
use rustc::mir::visit::{LvalueContext, Visitor};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::indexed_set::IdxSetBuf;
use util::pretty::{write_basic_block, dump_enabled, write_mir_intro};
use rustc::mir::transform::MirSource;
use rustc::ty::item_path;
use std::path::{PathBuf, Path};
use std::fs;
use rustc::ty::TyCtxt;
use std::io::{self, Write};

pub type LocalSet = IdxSetBuf<Local>;

#[derive(Eq, PartialEq, Clone)]
struct BlockInfo {
    defs: LocalSet,
    uses: LocalSet,
}

struct BlockInfoVisitor {
    pre_defs: LocalSet,
    defs: LocalSet,
    uses: LocalSet,
}

impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
    fn visit_lvalue(&mut self,
                    lvalue: &Lvalue<'tcx>,
                    context: LvalueContext<'tcx>,
                    location: Location) {
        if let Lvalue::Local(local) = *lvalue {
            match context {
                LvalueContext::Store |
                LvalueContext::Call |
                LvalueContext::StorageLive |
                LvalueContext::StorageDead => {
                    self.defs.add(&local);
                }
                LvalueContext::Projection(..) |
                LvalueContext::Borrow { .. } |
                LvalueContext::Inspect |
                LvalueContext::Consume |
                LvalueContext::Drop => {
                    // Ignore uses which are already defined in this block
                    if !self.pre_defs.contains(&local) {
                        self.uses.add(&local);
                    }
                }
            }
        }

        self.super_lvalue(lvalue, context, location)
    }
}

fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> BlockInfo {
    let mut visitor = BlockInfoVisitor {
        pre_defs: LocalSet::new_empty(locals),
        defs: LocalSet::new_empty(locals),
        uses: LocalSet::new_empty(locals),
    };

    let dummy_location = Location { block: BasicBlock::new(0), statement_index: 0 };

    for statement in &b.statements {
        visitor.visit_statement(BasicBlock::new(0), statement, dummy_location);
        visitor.pre_defs.union(&visitor.defs);
    }
    visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location);

    BlockInfo {
        defs: visitor.defs,
        uses: visitor.uses,
    }
}

pub struct LivenessResult {
    pub ins: IndexVec<BasicBlock, LocalSet>,
    pub outs: IndexVec<BasicBlock, LocalSet>,
}

pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>) -> LivenessResult {
    let locals = mir.local_decls.len();
    let def_use: IndexVec<_, _> = mir.basic_blocks().iter().map(|b| {
        block(b, locals)
    }).collect();

    let copy = |from: &IndexVec<BasicBlock, LocalSet>, to: &mut IndexVec<BasicBlock, LocalSet>| {
        for (i, set) in to.iter_enumerated_mut() {
            set.clone_from(&from[i]);
        }
    };

    let mut ins: IndexVec<_, _> = mir.basic_blocks()
        .indices()
        .map(|_| LocalSet::new_empty(locals)).collect();
    let mut outs = ins.clone();

    let mut ins_ = ins.clone();
    let mut outs_ = outs.clone();

    loop {
        copy(&ins, &mut ins_);
        copy(&outs, &mut outs_);

        for b in mir.basic_blocks().indices().rev() {
            // out = ∪ {ins of successors}
            outs[b].clear();
            for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() {
                outs[b].union(&ins[successor]);
            }

            // in = use ∪ (out - def)
            ins[b].clone_from(&outs[b]);
            ins[b].subtract(&def_use[b].defs);
            ins[b].union(&def_use[b].uses);
        }

        if ins_ == ins && outs_ == outs {
            break;
        }
    }

    LivenessResult {
        ins,
        outs,
    }
}

pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          source: MirSource,
                          mir: &Mir<'tcx>,
                          result: &LivenessResult) {
    if !dump_enabled(tcx, pass_name, source) {
        return;
    }
    let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below
        tcx.item_path_str(tcx.hir.local_def_id(source.item_id()))
    });
    dump_matched_mir_node(tcx, pass_name, &node_path,
                          source, mir, result);
}

fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   pass_name: &str,
                                   node_path: &str,
                                   source: MirSource,
                                   mir: &Mir<'tcx>,
                                   result: &LivenessResult) {
    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let file_name = format!("rustc.node{}{}-liveness.mir",
                            source.item_id(), pass_name);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?;
        writeln!(file, "// source = {:?}", source)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, source, mir, &mut file, result)?;
        Ok(())
    });
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write,
                              result: &LivenessResult)
                              -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        let print = |w: &mut Write, prefix, result: &IndexVec<BasicBlock, LocalSet>| {
            let live: Vec<String> = mir.local_decls.indices()
                .filter(|i| result[block].contains(i))
                .map(|i| format!("{:?}", i))
                .collect();
            writeln!(w, "{} {{{}}}", prefix, live.join(", "))
        };
        print(w, "   ", &result.ins)?;
        write_basic_block(tcx, block, mir, w)?;
        print(w, "   ", &result.outs)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

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

//! Liveness analysis which computes liveness of MIR local variables at the boundary of basic blocks

use rustc::mir::*;
use rustc::mir::visit::{LvalueContext, Visitor};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::indexed_set::IdxSetBuf;
use util::pretty::{write_basic_block, dump_enabled, write_mir_intro};
use rustc::mir::transform::MirSource;
use rustc::ty::item_path;
use std::path::{PathBuf, Path};
use std::fs;
use rustc::ty::TyCtxt;
use std::io::{self, Write};

pub type LocalSet = IdxSetBuf<Local>;

#[derive(Eq, PartialEq, Clone)]
struct BlockInfo {
    defs: LocalSet,
    uses: LocalSet,
}

struct BlockInfoVisitor {
    pre_defs: LocalSet,
    defs: LocalSet,
    uses: LocalSet,
}

impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
    fn visit_lvalue(&mut self,
                    lvalue: &Lvalue<'tcx>,
                    context: LvalueContext<'tcx>,
                    location: Location) {
        if let Lvalue::Local(local) = *lvalue {
            match context {
                LvalueContext::Store |

                // We let Call defined the result in both the success and unwind cases.
                // This may not be right.
                LvalueContext::Call |

                // Storage live and storage dead aren't proper defines, but we can ignore
                // values that come before them.
                LvalueContext::StorageLive |
                LvalueContext::StorageDead => {
                    self.defs.add(&local);
                }
                LvalueContext::Projection(..) |

                // Borrows only consider their local used at the point of the borrow.
                // This won't affect the results since we use this analysis for generators
                // and we only care about the result at suspension points. Borrows cannot
                // cross suspension points so this behavoir is unproblematic.
                LvalueContext::Borrow { .. } |

                LvalueContext::Inspect |
                LvalueContext::Consume |

                // We consider drops to always be uses of locals.
                // Drop eloboration should be run before this analysis otherwise
                // the results might be too pessimistic.
                LvalueContext::Drop => {
                    // Ignore uses which are already defined in this block
                    if !self.pre_defs.contains(&local) {
                        self.uses.add(&local);
                    }
                }
            }
        }

        self.super_lvalue(lvalue, context, location)
    }
}

fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> BlockInfo {
    let mut visitor = BlockInfoVisitor {
        pre_defs: LocalSet::new_empty(locals),
        defs: LocalSet::new_empty(locals),
        uses: LocalSet::new_empty(locals),
    };

    let dummy_location = Location { block: BasicBlock::new(0), statement_index: 0 };

    for statement in &b.statements {
        visitor.visit_statement(BasicBlock::new(0), statement, dummy_location);
        visitor.pre_defs.union(&visitor.defs);
    }
    visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location);

    BlockInfo {
        defs: visitor.defs,
        uses: visitor.uses,
    }
}

// This gives the result of the liveness analysis at the boundary of basic blocks
pub struct LivenessResult {
    pub ins: IndexVec<BasicBlock, LocalSet>,
    pub outs: IndexVec<BasicBlock, LocalSet>,
}

pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>) -> LivenessResult {
    let locals = mir.local_decls.len();
    let def_use: IndexVec<_, _> = mir.basic_blocks().iter().map(|b| {
        block(b, locals)
    }).collect();

    let copy = |from: &IndexVec<BasicBlock, LocalSet>, to: &mut IndexVec<BasicBlock, LocalSet>| {
        for (i, set) in to.iter_enumerated_mut() {
            set.clone_from(&from[i]);
        }
    };

    let mut ins: IndexVec<_, _> = mir.basic_blocks()
        .indices()
        .map(|_| LocalSet::new_empty(locals)).collect();
    let mut outs = ins.clone();

    let mut ins_ = ins.clone();
    let mut outs_ = outs.clone();

    loop {
        copy(&ins, &mut ins_);
        copy(&outs, &mut outs_);

        for b in mir.basic_blocks().indices().rev() {
            // out = ∪ {ins of successors}
            outs[b].clear();
            for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() {
                outs[b].union(&ins[successor]);
            }

            // in = use ∪ (out - def)
            ins[b].clone_from(&outs[b]);
            ins[b].subtract(&def_use[b].defs);
            ins[b].union(&def_use[b].uses);
        }

        if ins_ == ins && outs_ == outs {
            break;
        }
    }

    LivenessResult {
        ins,
        outs,
    }
}

pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          source: MirSource,
                          mir: &Mir<'tcx>,
                          result: &LivenessResult) {
    if !dump_enabled(tcx, pass_name, source) {
        return;
    }
    let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below
        tcx.item_path_str(tcx.hir.local_def_id(source.item_id()))
    });
    dump_matched_mir_node(tcx, pass_name, &node_path,
                          source, mir, result);
}

fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   pass_name: &str,
                                   node_path: &str,
                                   source: MirSource,
                                   mir: &Mir<'tcx>,
                                   result: &LivenessResult) {
    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let file_name = format!("rustc.node{}{}-liveness.mir",
                            source.item_id(), pass_name);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?;
        writeln!(file, "// source = {:?}", source)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, source, mir, &mut file, result)?;
        Ok(())
    });
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write,
                              result: &LivenessResult)
                              -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        let print = |w: &mut Write, prefix, result: &IndexVec<BasicBlock, LocalSet>| {
            let live: Vec<String> = mir.local_decls.indices()
                .filter(|i| result[block].contains(i))
                .map(|i| format!("{:?}", i))
                .collect();
            writeln!(w, "{} {{{}}}", prefix, live.join(", "))
        };
        print(w, "   ", &result.ins)?;
        write_basic_block(tcx, block, mir, w)?;
        print(w, "   ", &result.outs)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

<|endoftext|>


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

//! The compiler code necessary to implement the `#[derive]` extensions.

use syntax::ast::{self, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap;
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;
use syntax_pos::Span;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

macro_rules! path_std {
    ($($x:tt)*) => (
        ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) )
    )
}

pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod debug;
pub mod default;
pub mod custom;

#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/partial_ord.rs"]
pub mod partial_ord;
#[path="cmp/ord.rs"]
pub mod ord;

pub mod generic;

fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
    Span {
        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
            call_site: span,
            callee: codemap::NameAndSpan {
                format: codemap::MacroAttribute(intern(attr_name)),
                span: Some(span),
                allow_internal_unstable: true,
            },
        }),
        ..span
    }
}

pub fn expand_derive(cx: &mut ExtCtxt,
                 span: Span,
                 mitem: &MetaItem,
                 annotatable: Annotatable)
                 -> Vec<Annotatable> {
    debug!("expand_derive: span = {:?}", span);
    debug!("expand_derive: mitem = {:?}", mitem);
    debug!("expand_derive: annotatable input  = {:?}", annotatable);
    let mut item = match annotatable {
        Annotatable::Item(item) => item,
        other => {
            cx.span_err(span, "`derive` can only be applied to items");
            return vec![other]
        }
    };

    if mitem.value_str().is_some() {
        cx.span_err(mitem.span, "unexpected value in `derive`");
    }

    let mut traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
    if traits.is_empty() {
        cx.span_warn(mitem.span, "empty trait list in `derive`");
    }

    // First, weed out malformed #[derive]
    traits.retain(|titem| {
        if titem.word().is_none() {
            cx.span_err(titem.span, "malformed `derive` entry");
            false
        } else {
            true
        }
    });

    // Next, check for old-style #[derive(Foo)]
    //
    // These all get expanded to `#[derive_Foo]` and will get expanded first. If
    // we actually add any attributes here then we return to get those expanded
    // and then eventually we'll come back to finish off the other derive modes.
    let mut new_attributes = Vec::new();
    traits.retain(|titem| {
        let tword = titem.word().unwrap();
        let tname = tword.name();

        let derive_mode = ast::Ident::with_empty_ctxt(intern(&tname));
        let derive_mode = cx.resolver.resolve_derive_mode(derive_mode);
        if is_builtin_trait(&tname) || derive_mode.is_some() {
            return true
        }

        if !cx.ecfg.enable_custom_derive() {
            feature_gate::emit_feature_err(&cx.parse_sess,
                                           "custom_derive",
                                           titem.span,
                                           feature_gate::GateIssue::Language,
                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
        } else {
            let name = intern_and_get_ident(&format!("derive_{}", tname));
            let mitem = cx.meta_word(titem.span, name);
            new_attributes.push(cx.attribute(mitem.span, mitem));
        }
        false
    });
    if new_attributes.len() > 0 {
        item = item.map(|mut i| {
            i.attrs.extend(new_attributes);
            if traits.len() > 0 {
                let list = cx.meta_list(mitem.span,
                                        intern_and_get_ident("derive"),
                                        traits);
                i.attrs.push(cx.attribute(mitem.span, list));
            }
            i
        });
        return vec![Annotatable::Item(item)]
    }

    // Now check for macros-1.1 style custom #[derive].
    //
    // Expand each of them in order given, but *before* we expand any built-in
    // derive modes. The logic here is to:
    //
    // 1. Collect the remaining `#[derive]` annotations into a list. If
    //    there are any left, attach a `#[derive]` attribute to the item
    //    that we're currently expanding with the remaining derive modes.
    // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
    // 3. Expand the current item we're expanding, getting back a list of
    //    items that replace it.
    // 4. Extend the returned list with the current list of items we've
    //    collected so far.
    // 5. Return everything!
    //
    // If custom derive extensions end up threading through the `#[derive]`
    // attribute, we'll get called again later on to continue expanding
    // those modes.
    let macros_11_derive = traits.iter()
                                 .cloned()
                                 .enumerate()
                                 .filter(|&(_, ref name)| !is_builtin_trait(&name.name().unwrap()))
                                 .next();
    if let Some((i, titem)) = macros_11_derive {
        let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap()));
        let ext = cx.resolver.resolve_derive_mode(tname).unwrap();
        traits.remove(i);
        if traits.len() > 0 {
            item = item.map(|mut i| {
                let list = cx.meta_list(mitem.span,
                                        intern_and_get_ident("derive"),
                                        traits);
                i.attrs.push(cx.attribute(mitem.span, list));
                i
            });
        }
        let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap());
        let mitem = cx.meta_list(titem.span,
                                 intern_and_get_ident("derive"),
                                 vec![titem]);
        let item = Annotatable::Item(item);
        return ext.expand(cx, mitem.span, &mitem, item)
    }

    // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor
    // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here.

    // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
    // `#[structural_match]` attribute.
    if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") &&
       traits.iter().filter_map(|t| t.name()).any(|t| t == "Eq") {
        let structural_match = intern_and_get_ident("structural_match");
        let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
        let meta = cx.meta_word(span, structural_match);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is
    // the same as the copy implementation.
    //
    // Add a marker attribute here picked up during #[derive(Clone)]
    if traits.iter().filter_map(|t| t.name()).any(|t| t == "Clone") &&
       traits.iter().filter_map(|t| t.name()).any(|t| t == "Copy") {
        let marker = intern_and_get_ident("rustc_copy_clone_marker");
        let span = allow_unstable(cx, span, "derive(Copy, Clone)");
        let meta = cx.meta_word(span, marker);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    let mut items = Vec::new();
    for titem in traits.iter() {
        let tname = titem.word().unwrap().name();
        let name = intern_and_get_ident(&format!("derive({})", tname));
        let mitem = cx.meta_word(titem.span, name);

        let span = Span {
            expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                call_site: titem.span,
                callee: codemap::NameAndSpan {
                    format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
                    span: Some(titem.span),
                    allow_internal_unstable: true,
                },
            }),
            ..titem.span
        };

        let my_item = Annotatable::Item(item);
        expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| {
            items.push(a);
        });
        item = my_item.expect_item();
    }

    items.insert(0, Annotatable::Item(item));
    return items
}

macro_rules! derive_traits {
    ($( $name:expr => $func:path, )+) => {
        pub fn is_builtin_trait(name: &str) -> bool {
            match name {
                $( $name )|+ => true,
                _ => false,
            }
        }

        fn expand_builtin(name: &str,
                          ecx: &mut ExtCtxt,
                          span: Span,
                          mitem: &MetaItem,
                          item: &Annotatable,
                          push: &mut FnMut(Annotatable)) {
            match name {
                $(
                    $name => {
                        warn_if_deprecated(ecx, span, $name);
                        $func(ecx, span, mitem, item, push);
                    }
                )*
                _ => panic!("not a builtin derive mode: {}", name),
            }
        }
    }
}

derive_traits! {
    "Clone" => clone::expand_deriving_clone,

    "Hash" => hash::expand_deriving_hash,

    "RustcEncodable" => encodable::expand_deriving_rustc_encodable,

    "RustcDecodable" => decodable::expand_deriving_rustc_decodable,

    "PartialEq" => partial_eq::expand_deriving_partial_eq,
    "Eq" => eq::expand_deriving_eq,
    "PartialOrd" => partial_ord::expand_deriving_partial_ord,
    "Ord" => ord::expand_deriving_ord,

    "Debug" => debug::expand_deriving_debug,

    "Default" => default::expand_deriving_default,

    "Send" => bounds::expand_deriving_unsafe_bound,
    "Sync" => bounds::expand_deriving_unsafe_bound,
    "Copy" => bounds::expand_deriving_copy,

    // deprecated
    "Encodable" => encodable::expand_deriving_encodable,
    "Decodable" => decodable::expand_deriving_decodable,
}

#[inline] // because `name` is a compile-time constant
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
    if let Some(replacement) = match name {
        "Encodable" => Some("RustcEncodable"),
        "Decodable" => Some("RustcDecodable"),
        _ => None,
    } {
        ecx.span_warn(sp,
                      &format!("derive({}) is deprecated in favor of derive({})",
                               name,
                               replacement));
    }
}

/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
    let mut typaram = String::from(base);
    if let Annotatable::Item(ref item) = *item {
        match item.node {
            ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
            ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {
                for ty in ty_params.iter() {
                    typaram.push_str(&ty.ident.name.as_str());
                }
            }

            _ => {}
        }
    }

    typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
                  mut span: Span,
                  intrinsic: &str,
                  args: Vec<P<ast::Expr>>)
                  -> P<ast::Expr> {
    span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
        call_site: span,
        callee: codemap::NameAndSpan {
            format: codemap::MacroAttribute(intern("derive")),
            span: Some(span),
            allow_internal_unstable: true,
        },
    });

    let path = cx.std_path(&["intrinsics", intrinsic]);
    let call = cx.expr_call_global(span, path, args);

    cx.expr_block(P(ast::Block {
        stmts: vec![cx.stmt_expr(call)],
        id: ast::DUMMY_NODE_ID,
        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
        span: span,
    }))
}
<commit_msg>Expand `#[derive]` attribute macro invocations last.<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The compiler code necessary to implement the `#[derive]` extensions.

use syntax::ast::{self, MetaItem};
use syntax::attr::HasAttrs;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap;
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;
use syntax_pos::Span;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

macro_rules! path_std {
    ($($x:tt)*) => (
        ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) )
    )
}

pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod debug;
pub mod default;
pub mod custom;

#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/partial_ord.rs"]
pub mod partial_ord;
#[path="cmp/ord.rs"]
pub mod ord;

pub mod generic;

fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
    Span {
        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
            call_site: span,
            callee: codemap::NameAndSpan {
                format: codemap::MacroAttribute(intern(attr_name)),
                span: Some(span),
                allow_internal_unstable: true,
            },
        }),
        ..span
    }
}

pub fn expand_derive(cx: &mut ExtCtxt,
                 span: Span,
                 mitem: &MetaItem,
                 annotatable: Annotatable)
                 -> Vec<Annotatable> {
    debug!("expand_derive: span = {:?}", span);
    debug!("expand_derive: mitem = {:?}", mitem);
    debug!("expand_derive: annotatable input  = {:?}", annotatable);
    let mut item = match annotatable {
        Annotatable::Item(item) => item,
        other => {
            cx.span_err(span, "`derive` can only be applied to items");
            return vec![other]
        }
    };

    let mut derive_attrs = Vec::new();
    item = item.map_attrs(|attrs| {
        let partition = attrs.into_iter().partition(|attr| &attr.name() == "derive");
        derive_attrs = partition.0;
        partition.1
    });

    // Expand `#[derive]`s after other attribute macro invocations.
    if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
        return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
            attrs.push(cx.attribute(span, P(mitem.clone())));
            attrs.extend(derive_attrs);
            attrs
        }))];
    }

    let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
        if mitem.value_str().is_some() {
            cx.span_err(mitem.span, "unexpected value in `derive`");
        }

        let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
        if traits.is_empty() {
            cx.span_warn(mitem.span, "empty trait list in `derive`");
        }
        traits
    };

    let mut traits = get_traits(mitem, cx);
    for derive_attr in derive_attrs {
        traits.extend(get_traits(&derive_attr.node.value, cx));
    }

    // First, weed out malformed #[derive]
    traits.retain(|titem| {
        if titem.word().is_none() {
            cx.span_err(titem.span, "malformed `derive` entry");
            false
        } else {
            true
        }
    });

    // Next, check for old-style #[derive(Foo)]
    //
    // These all get expanded to `#[derive_Foo]` and will get expanded first. If
    // we actually add any attributes here then we return to get those expanded
    // and then eventually we'll come back to finish off the other derive modes.
    let mut new_attributes = Vec::new();
    traits.retain(|titem| {
        let tword = titem.word().unwrap();
        let tname = tword.name();

        let derive_mode = ast::Ident::with_empty_ctxt(intern(&tname));
        let derive_mode = cx.resolver.resolve_derive_mode(derive_mode);
        if is_builtin_trait(&tname) || derive_mode.is_some() {
            return true
        }

        if !cx.ecfg.enable_custom_derive() {
            feature_gate::emit_feature_err(&cx.parse_sess,
                                           "custom_derive",
                                           titem.span,
                                           feature_gate::GateIssue::Language,
                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
        } else {
            let name = intern_and_get_ident(&format!("derive_{}", tname));
            let mitem = cx.meta_word(titem.span, name);
            new_attributes.push(cx.attribute(mitem.span, mitem));
        }
        false
    });
    if new_attributes.len() > 0 {
        item = item.map(|mut i| {
            i.attrs.extend(new_attributes);
            if traits.len() > 0 {
                let list = cx.meta_list(mitem.span,
                                        intern_and_get_ident("derive"),
                                        traits);
                i.attrs.push(cx.attribute(mitem.span, list));
            }
            i
        });
        return vec![Annotatable::Item(item)]
    }

    // Now check for macros-1.1 style custom #[derive].
    //
    // Expand each of them in order given, but *before* we expand any built-in
    // derive modes. The logic here is to:
    //
    // 1. Collect the remaining `#[derive]` annotations into a list. If
    //    there are any left, attach a `#[derive]` attribute to the item
    //    that we're currently expanding with the remaining derive modes.
    // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
    // 3. Expand the current item we're expanding, getting back a list of
    //    items that replace it.
    // 4. Extend the returned list with the current list of items we've
    //    collected so far.
    // 5. Return everything!
    //
    // If custom derive extensions end up threading through the `#[derive]`
    // attribute, we'll get called again later on to continue expanding
    // those modes.
    let macros_11_derive = traits.iter()
                                 .cloned()
                                 .enumerate()
                                 .filter(|&(_, ref name)| !is_builtin_trait(&name.name().unwrap()))
                                 .next();
    if let Some((i, titem)) = macros_11_derive {
        let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap()));
        let ext = cx.resolver.resolve_derive_mode(tname).unwrap();
        traits.remove(i);
        if traits.len() > 0 {
            item = item.map(|mut i| {
                let list = cx.meta_list(mitem.span,
                                        intern_and_get_ident("derive"),
                                        traits);
                i.attrs.push(cx.attribute(mitem.span, list));
                i
            });
        }
        let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap());
        let mitem = cx.meta_list(titem.span,
                                 intern_and_get_ident("derive"),
                                 vec![titem]);
        let item = Annotatable::Item(item);
        return ext.expand(cx, mitem.span, &mitem, item)
    }

    // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor
    // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here.

    // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
    // `#[structural_match]` attribute.
    if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") &&
       traits.iter().filter_map(|t| t.name()).any(|t| t == "Eq") {
        let structural_match = intern_and_get_ident("structural_match");
        let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
        let meta = cx.meta_word(span, structural_match);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is
    // the same as the copy implementation.
    //
    // Add a marker attribute here picked up during #[derive(Clone)]
    if traits.iter().filter_map(|t| t.name()).any(|t| t == "Clone") &&
       traits.iter().filter_map(|t| t.name()).any(|t| t == "Copy") {
        let marker = intern_and_get_ident("rustc_copy_clone_marker");
        let span = allow_unstable(cx, span, "derive(Copy, Clone)");
        let meta = cx.meta_word(span, marker);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    let mut items = Vec::new();
    for titem in traits.iter() {
        let tname = titem.word().unwrap().name();
        let name = intern_and_get_ident(&format!("derive({})", tname));
        let mitem = cx.meta_word(titem.span, name);

        let span = Span {
            expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                call_site: titem.span,
                callee: codemap::NameAndSpan {
                    format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
                    span: Some(titem.span),
                    allow_internal_unstable: true,
                },
            }),
            ..titem.span
        };

        let my_item = Annotatable::Item(item);
        expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| {
            items.push(a);
        });
        item = my_item.expect_item();
    }

    items.insert(0, Annotatable::Item(item));
    return items
}

macro_rules! derive_traits {
    ($( $name:expr => $func:path, )+) => {
        pub fn is_builtin_trait(name: &str) -> bool {
            match name {
                $( $name )|+ => true,
                _ => false,
            }
        }

        fn expand_builtin(name: &str,
                          ecx: &mut ExtCtxt,
                          span: Span,
                          mitem: &MetaItem,
                          item: &Annotatable,
                          push: &mut FnMut(Annotatable)) {
            match name {
                $(
                    $name => {
                        warn_if_deprecated(ecx, span, $name);
                        $func(ecx, span, mitem, item, push);
                    }
                )*
                _ => panic!("not a builtin derive mode: {}", name),
            }
        }
    }
}

derive_traits! {
    "Clone" => clone::expand_deriving_clone,

    "Hash" => hash::expand_deriving_hash,

    "RustcEncodable" => encodable::expand_deriving_rustc_encodable,

    "RustcDecodable" => decodable::expand_deriving_rustc_decodable,

    "PartialEq" => partial_eq::expand_deriving_partial_eq,
    "Eq" => eq::expand_deriving_eq,
    "PartialOrd" => partial_ord::expand_deriving_partial_ord,
    "Ord" => ord::expand_deriving_ord,

    "Debug" => debug::expand_deriving_debug,

    "Default" => default::expand_deriving_default,

    "Send" => bounds::expand_deriving_unsafe_bound,
    "Sync" => bounds::expand_deriving_unsafe_bound,
    "Copy" => bounds::expand_deriving_copy,

    // deprecated
    "Encodable" => encodable::expand_deriving_encodable,
    "Decodable" => decodable::expand_deriving_decodable,
}

#[inline] // because `name` is a compile-time constant
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
    if let Some(replacement) = match name {
        "Encodable" => Some("RustcEncodable"),
        "Decodable" => Some("RustcDecodable"),
        _ => None,
    } {
        ecx.span_warn(sp,
                      &format!("derive({}) is deprecated in favor of derive({})",
                               name,
                               replacement));
    }
}

/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
    let mut typaram = String::from(base);
    if let Annotatable::Item(ref item) = *item {
        match item.node {
            ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
            ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {
                for ty in ty_params.iter() {
                    typaram.push_str(&ty.ident.name.as_str());
                }
            }

            _ => {}
        }
    }

    typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
                  mut span: Span,
                  intrinsic: &str,
                  args: Vec<P<ast::Expr>>)
                  -> P<ast::Expr> {
    span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
        call_site: span,
        callee: codemap::NameAndSpan {
            format: codemap::MacroAttribute(intern("derive")),
            span: Some(span),
            allow_internal_unstable: true,
        },
    });

    let path = cx.std_path(&["intrinsics", intrinsic]);
    let call = cx.expr_call_global(span, path, args);

    cx.expr_block(P(ast::Block {
        stmts: vec![cx.stmt_expr(call)],
        id: ast::DUMMY_NODE_ID,
        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
        span: span,
    }))
}
<|endoftext|>