<commit_before>// Copyright 2016 Serde YAML Developers
//
// 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.

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_yaml;

extern crate unindent;
use unindent::unindent;

use std::fmt::Debug;

fn test_error<T>(yaml: &str, expected: &str)
    where T: serde::Deserialize + Debug
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, format!("{}", result.unwrap_err()));
}

#[test]
fn test_incorrect_type() {
    let yaml = unindent("
        ---
        str");
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(&yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        d: bool,
    }
    let yaml = unindent("
        ---
        b:
          - C:
              d: fase");
    let expected = "b[0].C.d: invalid type: string \"fase\", expected a boolean at line 4 column 10";
    test_error::<A>(&yaml, expected);
}

#[test]
fn test_empty() {
    let yaml = "";
    let expected = "EOF while parsing a value";
    test_error::<String>(&yaml, expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        v: bool,
        w: bool,
    }
    let yaml = unindent("
        ---
        v: true");
    let expected = "missing field `w` at line 2 column 2";
    test_error::<Basic>(&yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = unindent("
        ---
        *some");
    let expected = "while parsing node, found unknown anchor at line 2 column 1";
    test_error::<String>(&yaml, expected);
}

#[test]
fn test_two_documents() {
    let yaml = unindent("
        ---
        0
        ---
        1");
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(&yaml, expected);
}

#[test]
fn test_variant_map_wrong_size() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = unindent(r#"
        ---
        "V": 16
        "other": 32"#);
    let expected = "invalid length 2, expected map containing 1 entry";
    test_error::<E>(&yaml, expected);
}

#[test]
fn test_variant_not_a_map() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = unindent(r#"
        ---
        - "V""#);
    let expected = "invalid type: sequence, expected string or singleton map at line 2 column 1";
    test_error::<E>(&yaml, expected);
}

#[test]
fn test_variant_not_string() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(bool),
    }
    let yaml = unindent(r#"
        ---
        {}: true"#);
    let expected = "invalid type: map, expected variant of enum `E` at line 2 column 1";
    test_error::<E>(&yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = unindent("
        ---
        !!bool str");
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 8";
    test_error::<bool>(&yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = unindent("
        ---
        !!int str");
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 7";
    test_error::<i64>(&yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = unindent("
        ---
        !!float str");
    let expected = "invalid value: string \"str\", expected a float at line 2 column 9";
    test_error::<f64>(&yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = unindent("
        ---
        !!null str");
    let expected = "invalid value: string \"str\", expected null at line 2 column 8";
    test_error::<()>(&yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = unindent("
        ---
        [0, 0]");
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(&yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = unindent("
        ---
        [0, 0, 0]");
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(&yaml, expected);
}
<commit_msg>Fix needless borrow lint in test<commit_after>// Copyright 2016 Serde YAML Developers
//
// 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.

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_yaml;

extern crate unindent;
use unindent::unindent;

use std::fmt::Debug;

fn test_error<T>(yaml: &str, expected: &str)
    where T: serde::Deserialize + Debug
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, format!("{}", result.unwrap_err()));
}

#[test]
fn test_incorrect_type() {
    let yaml = unindent("
        ---
        str");
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(&yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        d: bool,
    }
    let yaml = unindent("
        ---
        b:
          - C:
              d: fase");
    let expected = "b[0].C.d: invalid type: string \"fase\", expected a boolean at line 4 column 10";
    test_error::<A>(&yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        v: bool,
        w: bool,
    }
    let yaml = unindent("
        ---
        v: true");
    let expected = "missing field `w` at line 2 column 2";
    test_error::<Basic>(&yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = unindent("
        ---
        *some");
    let expected = "while parsing node, found unknown anchor at line 2 column 1";
    test_error::<String>(&yaml, expected);
}

#[test]
fn test_two_documents() {
    let yaml = unindent("
        ---
        0
        ---
        1");
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(&yaml, expected);
}

#[test]
fn test_variant_map_wrong_size() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = unindent(r#"
        ---
        "V": 16
        "other": 32"#);
    let expected = "invalid length 2, expected map containing 1 entry";
    test_error::<E>(&yaml, expected);
}

#[test]
fn test_variant_not_a_map() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = unindent(r#"
        ---
        - "V""#);
    let expected = "invalid type: sequence, expected string or singleton map at line 2 column 1";
    test_error::<E>(&yaml, expected);
}

#[test]
fn test_variant_not_string() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(bool),
    }
    let yaml = unindent(r#"
        ---
        {}: true"#);
    let expected = "invalid type: map, expected variant of enum `E` at line 2 column 1";
    test_error::<E>(&yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = unindent("
        ---
        !!bool str");
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 8";
    test_error::<bool>(&yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = unindent("
        ---
        !!int str");
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 7";
    test_error::<i64>(&yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = unindent("
        ---
        !!float str");
    let expected = "invalid value: string \"str\", expected a float at line 2 column 9";
    test_error::<f64>(&yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = unindent("
        ---
        !!null str");
    let expected = "invalid value: string \"str\", expected null at line 2 column 8";
    test_error::<()>(&yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = unindent("
        ---
        [0, 0]");
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(&yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = unindent("
        ---
        [0, 0, 0]");
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(&yaml, expected);
}
<|endoftext|>


<commit_before>// -*- rust -*-
// error-pattern:9:2

/* 1
 * 2
 * 3
 */
fn main() {
  %; // parse error on line 9, but is reported on line 6 instead.
}
<commit_msg>Fix up test for last commit<commit_after>// -*- rust -*-
// error-pattern:9:3

/* 1
 * 2
 * 3
 */
fn main() {
  %; // parse error on line 9, but is reported on line 6 instead.
}
<|endoftext|>


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

//! Logging wrapper to be used throughout all crates in the workspace
use std::fs::OpenOptions;
use std::sync::Mutex;
use slog::{Logger, Drain, Level, LevelFilter, Duplicate, Discard};
use slog_term;
use slog_async;

use types::{LogLevel, LoggingConfig};

fn convert_log_level(in_level: &LogLevel) -> Level {
	match *in_level {
		LogLevel::Info => Level::Info,
		LogLevel::Critical => Level::Critical,
		LogLevel::Warning => Level::Warning,
		LogLevel::Debug => Level::Debug,
		LogLevel::Trace => Level::Trace,
		LogLevel::Error => Level::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explcitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
	/// And a static reference to the logger itself, accessible from all crates
	pub static ref LOGGER: Logger = {
		let was_init = WAS_INIT.lock().unwrap().clone();
		let config = LOGGING_CONFIG.lock().unwrap();
		let slog_level_stdout = convert_log_level(&config.stdout_log_level);
		let slog_level_file = convert_log_level(&config.file_log_level);

		//Terminal output drain
		let terminal_decorator = slog_term::TermDecorator::new().build();
		let terminal_drain = slog_term::FullFormat::new(terminal_decorator).build().fuse();
		let terminal_drain = LevelFilter::new(terminal_drain, slog_level_stdout).fuse();
		let mut terminal_drain = slog_async::Async::new(terminal_drain).build().fuse();

		if !config.log_to_stdout || !was_init {
			terminal_drain = slog_async::Async::new(Discard{}).build().fuse();
		}

		let mut file_drain_final = slog_async::Async::new(Discard{}).build().fuse();

		if config.log_to_file && was_init {
			//File drain
			let file = OpenOptions::new()
				.create(true)
				.write(true)
				.append(config.log_file_append)
				.truncate(false)
				.open(&config.log_file_path)
				.unwrap();

			let file_decorator = slog_term::PlainDecorator::new(file);
			let file_drain = slog_term::FullFormat::new(file_decorator).build().fuse();
			let file_drain = LevelFilter::new(file_drain, slog_level_file).fuse();
			file_drain_final = slog_async::Async::new(file_drain).build().fuse();
		}

		//Compose file and terminal drains
		let composite_drain = Duplicate::new(terminal_drain, file_drain_final).fuse();

		let log = Logger::root(composite_drain, o!());
		log
	};
}

/// Initialises the logger with the given configuration

pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let mut config_ref = LOGGING_CONFIG.lock().unwrap();
		*config_ref = c.clone();
		let mut was_init_ref = WAS_INIT.lock().unwrap();
		*was_init_ref = true;
	}
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
  let mut was_init_ref = WAS_INIT.lock().unwrap();
	if was_init_ref {
		return;
	}
  let mut config_ref = LOGGING_CONFIG.lock().unwrap();
  *config_ref = LoggingConfig::default();
  *was_init_ref = true;
}

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

//! Logging wrapper to be used throughout all crates in the workspace
use std::fs::OpenOptions;
use std::sync::Mutex;
use std::ops::Deref;
use slog::{Logger, Drain, Level, LevelFilter, Duplicate, Discard};
use slog_term;
use slog_async;

use types::{LogLevel, LoggingConfig};

fn convert_log_level(in_level: &LogLevel) -> Level {
	match *in_level {
		LogLevel::Info => Level::Info,
		LogLevel::Critical => Level::Critical,
		LogLevel::Warning => Level::Warning,
		LogLevel::Debug => Level::Debug,
		LogLevel::Trace => Level::Trace,
		LogLevel::Error => Level::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explcitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
	/// And a static reference to the logger itself, accessible from all crates
	pub static ref LOGGER: Logger = {
		let was_init = WAS_INIT.lock().unwrap().clone();
		let config = LOGGING_CONFIG.lock().unwrap();
		let slog_level_stdout = convert_log_level(&config.stdout_log_level);
		let slog_level_file = convert_log_level(&config.file_log_level);

		//Terminal output drain
		let terminal_decorator = slog_term::TermDecorator::new().build();
		let terminal_drain = slog_term::FullFormat::new(terminal_decorator).build().fuse();
		let terminal_drain = LevelFilter::new(terminal_drain, slog_level_stdout).fuse();
		let mut terminal_drain = slog_async::Async::new(terminal_drain).build().fuse();

		if !config.log_to_stdout || !was_init {
			terminal_drain = slog_async::Async::new(Discard{}).build().fuse();
		}

		let mut file_drain_final = slog_async::Async::new(Discard{}).build().fuse();

		if config.log_to_file && was_init {
			//File drain
			let file = OpenOptions::new()
				.create(true)
				.write(true)
				.append(config.log_file_append)
				.truncate(false)
				.open(&config.log_file_path)
				.unwrap();

			let file_decorator = slog_term::PlainDecorator::new(file);
			let file_drain = slog_term::FullFormat::new(file_decorator).build().fuse();
			let file_drain = LevelFilter::new(file_drain, slog_level_file).fuse();
			file_drain_final = slog_async::Async::new(file_drain).build().fuse();
		}

		//Compose file and terminal drains
		let composite_drain = Duplicate::new(terminal_drain, file_drain_final).fuse();

		let log = Logger::root(composite_drain, o!());
		log
	};
}

/// Initialises the logger with the given configuration

pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let mut config_ref = LOGGING_CONFIG.lock().unwrap();
		*config_ref = c.clone();
		let mut was_init_ref = WAS_INIT.lock().unwrap();
		*was_init_ref = true;
	}
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
  let mut was_init_ref = WAS_INIT.lock().unwrap();
	if *was_init_ref.deref() {
		return;
	}
  let mut config_ref = LOGGING_CONFIG.lock().unwrap();
  *config_ref = LoggingConfig::default();
  *was_init_ref = true;
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use ast::Type;
use bytecode::instruction::{Instruction, Operand};
use bytecode::function::{ByteCodeFunction};

struct VarInfo
{
    typ: Type,
    initializer: Operand,
    num_stores: usize,
}

impl VarInfo
{
    fn new(typ: &Type) -> VarInfo
    {
        VarInfo{
            typ: typ.clone(),
            initializer: Operand::Nil,
            num_stores: 0,
        }
    }

    fn is_primitive(&self) -> bool
    {
        match self.typ
        {
            Type::Int | Type::UInt | Type::Float | Type::Bool | Type::String => true,
            _ => false,
        }
    }

    fn can_be_eliminated(&self) -> bool
    {
        self.num_stores == 0 && self.is_primitive()
    }

    fn can_be_replaced_by_initializer(&self) -> bool
    {
        self.num_stores == 1 && self.is_primitive()
    }
}

struct VarInfoMap(HashMap<String, VarInfo>);

impl VarInfoMap
{
    fn remove(&mut self, name: &str)
    {
        self.0.remove(name);
    }

    fn store(&mut self, name: &str, initializer: &Operand)
    {
        self.0.get_mut(name)
            .map(|var_info| {
                var_info.initializer = initializer.clone();
                var_info.num_stores += 1;
            });
    }
}

fn replace_var_by_initializer(instr: &mut Instruction, var: &str, initializer: &Operand)
{
    let do_replace = |op: &mut Operand| {
        let replace = match *op
        {
            Operand::Var(ref mut v) if v.name == var => true,
            _ => false
        };

        if replace {
            *op = initializer.clone();
        }
    };

    match *instr
    {
        Instruction::Store{ref mut src, ..} => do_replace(src),
        Instruction::LoadMember{ref mut member_index, ..} => do_replace(member_index),
        Instruction::UnaryOp{ref mut src, ..} => do_replace(src),
        Instruction::BinaryOp{ref mut left, ref mut right, ..} => {
            do_replace(left);
            do_replace(right);
        },
        Instruction::Call{ref mut args, ..} => {
            for arg in args {
                do_replace(arg)
            }
        },
        Instruction::Slice{ref mut start, ref mut len, ..} => {
            do_replace(start);
            do_replace(len);
        },
        Instruction::Cast{ref mut src, ..} => do_replace(src),
        Instruction::Return(ref mut v) => do_replace(v),
        Instruction::BranchIf{ref mut cond, ..} => do_replace(cond),
        _ => (),
    }
}

fn eliminate_vars_pass(func: &mut ByteCodeFunction) -> usize
{
    let mut vars = VarInfoMap(HashMap::new());

    func.for_each_instruction(|instr: &Instruction| {
        match *instr
        {
            Instruction::StackAlloc(ref var) => {
                vars.0.insert(var.name.clone(), VarInfo::new(&var.typ));
            },

            Instruction::Store{ref dst, ref src} => {
                vars.store(&dst.name, src);
            },

            Instruction::Cast{ref dst, ..} |
            Instruction::Load{ref dst, ..} |
            Instruction::UnaryOp{ref dst, ..} |
            Instruction::BinaryOp{ref dst, ..} |
            Instruction::Slice{ref dst, ..} |
            Instruction::Call{ref dst, ..} => {
                vars.remove(&dst.name);
            },

            Instruction::LoadMember{ref obj, ..} |
            Instruction::AddressOf{ref obj, ..} => {
                vars.remove(&obj.name);
            },

            Instruction::GetProperty{ref obj, ref dst, ..} => {
                vars.remove(&obj.name);
                vars.remove(&dst.name);
            }

            _ => (),
        }

        true
    });

    let mut eliminated = 0;
    for (var, var_info) in &vars.0 {
        if !var_info.can_be_eliminated() && !var_info.can_be_replaced_by_initializer() {
            continue;
        }

        eliminated += 1;

        func.remove_instruction(|instr: &Instruction| {
            match *instr {
                Instruction::StackAlloc(ref v) if v.name == *var => true,
                Instruction::Store{ref dst, ..} if dst.name == *var => true,
                _ => false,
            }
        });

        if var_info.can_be_replaced_by_initializer() {
            func.for_each_instruction_mut(|instr| {
                replace_var_by_initializer(instr, &var, &var_info.initializer);
                true
            });
        }
    }
    eliminated
}

pub fn eliminate_vars(func: &mut ByteCodeFunction)
{
    while eliminate_vars_pass(func) > 0 {
    }
}
<commit_msg>Eliminate one variable at a time, in the variable elimination pass, so we don't trip up when one variable elimination depends on another one.<commit_after>use std::collections::HashMap;
use ast::Type;
use bytecode::instruction::{Instruction, Operand};
use bytecode::function::{ByteCodeFunction};

struct VarInfo
{
    typ: Type,
    initializer: Operand,
    num_stores: usize,
}

impl VarInfo
{
    fn new(typ: &Type) -> VarInfo
    {
        VarInfo{
            typ: typ.clone(),
            initializer: Operand::Nil,
            num_stores: 0,
        }
    }

    fn is_primitive(&self) -> bool
    {
        match self.typ
        {
            Type::Int | Type::UInt | Type::Float | Type::Bool | Type::String => true,
            _ => false,
        }
    }

    fn can_be_eliminated(&self) -> bool
    {
        self.num_stores == 0 && self.is_primitive()
    }

    fn can_be_replaced_by_initializer(&self) -> bool
    {
        self.num_stores == 1 && self.is_primitive()
    }
}

struct VarInfoMap(HashMap<String, VarInfo>);

impl VarInfoMap
{
    fn remove(&mut self, name: &str)
    {
        self.0.remove(name);
    }

    fn store(&mut self, name: &str, initializer: &Operand)
    {
        self.0.get_mut(name)
            .map(|var_info| {
                var_info.initializer = initializer.clone();
                var_info.num_stores += 1;
            });
    }
}

fn replace_var_by_initializer(instr: &mut Instruction, var: &str, initializer: &Operand)
{
    let do_replace = |op: &mut Operand| {
        let replace = match *op
        {
            Operand::Var(ref mut v) if v.name == var => true,
            _ => false
        };

        if replace {
            *op = initializer.clone();
        }
    };

    match *instr
    {
        Instruction::Store{ref mut src, ..} => do_replace(src),
        Instruction::LoadMember{ref mut member_index, ..} => do_replace(member_index),
        Instruction::UnaryOp{ref mut src, ..} => do_replace(src),
        Instruction::BinaryOp{ref mut left, ref mut right, ..} => {
            do_replace(left);
            do_replace(right);
        },
        Instruction::Call{ref mut args, ..} => {
            for arg in args {
                do_replace(arg)
            }
        },
        Instruction::Slice{ref mut start, ref mut len, ..} => {
            do_replace(start);
            do_replace(len);
        },
        Instruction::Cast{ref mut src, ..} => do_replace(src),
        Instruction::Return(ref mut v) => do_replace(v),
        Instruction::BranchIf{ref mut cond, ..} => do_replace(cond),
        _ => (),
    }
}

fn eliminate_vars_pass(func: &mut ByteCodeFunction) -> usize
{
    let mut vars = VarInfoMap(HashMap::new());

    func.for_each_instruction(|instr: &Instruction| {
        match *instr
        {
            Instruction::StackAlloc(ref var) => {
                vars.0.insert(var.name.clone(), VarInfo::new(&var.typ));
            },

            Instruction::Store{ref dst, ref src} => {
                vars.store(&dst.name, src);
            },

            Instruction::Cast{ref dst, ..} |
            Instruction::Load{ref dst, ..} |
            Instruction::UnaryOp{ref dst, ..} |
            Instruction::BinaryOp{ref dst, ..} |
            Instruction::Slice{ref dst, ..} |
            Instruction::Call{ref dst, ..} => {
                vars.remove(&dst.name);
            },

            Instruction::LoadMember{ref obj, ..} |
            Instruction::AddressOf{ref obj, ..} => {
                vars.remove(&obj.name);
            },

            Instruction::GetProperty{ref obj, ref dst, ..} => {
                vars.remove(&obj.name);
                vars.remove(&dst.name);
            }

            _ => (),
        }

        true
    });

    let mut eliminated = 0;
    for (var, var_info) in &vars.0 {
        if !var_info.can_be_eliminated() && !var_info.can_be_replaced_by_initializer() {
            continue;
        }

        eliminated += 1;

        func.remove_instruction(|instr: &Instruction| {
            match *instr {
                Instruction::StackAlloc(ref v) if v.name == *var => true,
                Instruction::Store{ref dst, ..} if dst.name == *var => true,
                _ => false,
            }
        });

        if var_info.can_be_replaced_by_initializer() {
            func.for_each_instruction_mut(|instr| {
                replace_var_by_initializer(instr, &var, &var_info.initializer);
                true
            });
        }
        break; // Only do one per time
    }
    eliminated
}

pub fn eliminate_vars(func: &mut ByteCodeFunction)
{
    while eliminate_vars_pass(func) > 0 {
    }
}
<|endoftext|>


<commit_before>
use euclid::{Point2D, Size2D};
use std::cmp::{max, min};
use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map;
use std::fmt;
use std::hash::Hash;
use std::i32;
use std::iter::{FromIterator, IntoIterator};

/// A structure for storing a piece of a grid map.
///
/// All contents are guaranteed to be stored in the rectangle between (0, 0) (inclusive) and `dim`
/// (exclusive).
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Prefab<T> {
    terrain: HashMap<Point2D<i32>, usize>,
    elements: Vec<T>,
    dim: Size2D<u32>,
}

impl<T: Clone + Eq + Hash> Prefab<T> {
    fn new() -> Prefab<T> {
        Prefab {
            terrain: HashMap::new(),
            elements: Vec::new(),
            dim: Size2D::new(0, 0),
        }
    }

    pub fn get(&self, pos: Point2D<i32>) -> Option<&T> {
        self.terrain.get(&pos).map(|&idx| &self.elements[idx])
    }

    pub fn map<F: FnMut(T) -> U, U>(self, f: F) -> Prefab<U> {
        Prefab {
            terrain: self.terrain,
            elements: self.elements.into_iter().map(f).collect(),
            dim: self.dim,
        }
    }

    pub fn dim(&self) -> Size2D<u32> { self.dim }

    pub fn iter(&self) -> PrefabIterator<T> {
        PrefabIterator {
            prefab: self,
            iter: self.terrain.iter(),
        }
    }
}

pub struct PrefabIterator<'a, T: 'a> {
    prefab: &'a Prefab<T>,
    iter: hash_map::Iter<'a, Point2D<i32>, usize>,
}

impl<'a, T: 'a> Iterator for PrefabIterator<'a, T> {
    type Item = (Point2D<i32>, &'a T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            Some((&pos, &idx)) => Some((pos, &self.prefab.elements[idx])),
            _ => None,
        }
    }
}

impl<T: Clone + Eq + Hash> FromIterator<(Point2D<i32>, T)> for Prefab<T> {
    fn from_iter<I: IntoIterator<Item = (Point2D<i32>, T)>>(iter: I) -> Self {
        // List of unique values.
        let mut element_idx: HashMap<T, usize> = HashMap::new();
        let mut ret = Prefab::new();

        let mut min_x = i32::MAX;
        let mut min_y = i32::MAX;

        // Temporary storage before positions have been normalized.
        let mut temp_buffer = Vec::new();

        for (p, e) in iter {
            min_x = min(min_x, p.x);
            min_y = min(min_y, p.y);

            let val = *element_idx
                           .entry(e.clone())
                           .or_insert_with(|| {
                                               ret.elements.push(e);
                                               ret.elements.len() - 1
                                           });

            temp_buffer.push((p, val));
        }

        // Normalization: Snap bounding box to origin.
        let mut max_x = 0;
        let mut max_y = 0;

        for (mut p, e) in temp_buffer {
            p.x -= min_x;
            assert!(p.x >= 0);
            p.y -= min_y;
            assert!(p.y >= 0);

            max_x = max(p.x as u32, max_x);
            max_y = max(p.y as u32, max_y);

            ret.terrain.insert(p, e);
        }

        ret.dim = Size2D::new(max_x + 1, max_y + 1);

        ret
    }
}

impl Prefab<char> {
    fn from_text<F>(map: &str, project: F) -> Prefab<char>
        where F: Fn(usize, usize) -> (i32, i32)
    {
        let mut buf = Vec::new();
        for (y, line) in map.lines().enumerate() {
            for (x, c) in line.chars().enumerate() {
                let (map_x, map_y) = project(x, y);
                if !c.is_whitespace() {
                    buf.push((Point2D::new(map_x, map_y), c));
                }
            }
        }

        Prefab::from_iter(buf.into_iter())
    }

    pub fn from_text_map(map: &str) -> Prefab<char> {
        Prefab::from_text(map, |x, y| (x as i32, y as i32))
    }

    pub fn from_text_hexmap(map: &str) -> Prefab<char> {
        Prefab::from_text(map, |x, y| ((x + y) as i32 / 2, y as i32))
    }
}

impl<T: fmt::Display + Clone + Eq + Hash> fmt::Display for Prefab<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for y in 0..self.dim.height {
            for x in 0..self.dim.width {
                if let Some(c) = self.get(Point2D::new(x as i32, y as i32)) {
                    write!(f, "{}", c)?;
                } else {
                    write!(f, " ")?;
                }
            }
            writeln!(f, "")?;
        }
        Ok(())
    }
}

impl<T: fmt::Display + Clone + Eq + Hash> Prefab<T> {
    /// Return a wrapper for printing the map in hex layout.
    ///
    /// Without the wrapper the print format will be a traditional dense text map.
    pub fn hexmap_display(&self) -> HexmapDisplay<T> { HexmapDisplay(self) }
}

/// Wrapper type for displaying the `Prefab` as a text hexmap.
pub struct HexmapDisplay<'a, T: 'a>(&'a Prefab<T>);

impl<'a, T: fmt::Display + Clone + Eq + Hash> fmt::Display for HexmapDisplay<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let max_width = (self.0.dim.width * 2 + self.0.dim.height) as i32;

        // Find the smallest displayed x-coordinate that actually shows up in the map.
        let min_x = (0..self.0.dim.width)
            .flat_map(move |x| {
                          (0..self.0.dim.height).map(move |y| Point2D::new(x as i32, y as i32))
                      })
            .filter(|&p| self.0.get(p).is_some())
            .map(|p| p.x * 2 - p.y)
            .min()
            .unwrap_or(0);

        for y in 0..(self.0.dim.height as i32) {
            for x in min_x..(min_x + max_width) {
                if (x - y) % 2 != 0 {
                    write!(f, " ")?;
                    continue;
                }
                let map_x = (x + y) / 2;
                let map_y = y;
                if let Some(c) = self.0.get(Point2D::new(map_x, map_y)) {
                    write!(f, "{}", c)?;
                } else {
                    write!(f, " ")?;
                }
            }
            writeln!(f, "")?;
        }
        Ok(())
    }
}

/// Build a text map legend given an alphabet and a sequence of elements.
///
/// Each unique element will be assigned a letter from the alphabet. A preference function can
/// provide an additional alphabet prefix for specific values, which will be sampled before the
/// main alphabet. This will allow having standard special characters for eg. certain types of
/// terrain tiles. When no special alphabet is required, the preference function can return an
/// empty string.
pub struct LegendBuilder<T, F> {
    /// The generated legend map.
    pub legend: BTreeMap<char, T>,
    /// Set to true if an add operation failed to assign a symbol.
    pub out_of_alphabet: bool,
    seen_values: BTreeMap<T, char>,
    prefix_fn: F,
    alphabet: String,
}

impl<T, F> LegendBuilder<T, F>
    where T: Ord + Eq + Clone,
          F: FnMut(&T) -> &'static str
{
    /// Initialize the legend builder.
    pub fn new(alphabet: String, prefix_fn: F) -> LegendBuilder<T, F> {
        LegendBuilder {
            legend: BTreeMap::new(),
            out_of_alphabet: false,
            seen_values: BTreeMap::new(),
            prefix_fn: prefix_fn,
            alphabet: alphabet,
        }
    }

    /// Show a value to `LegendBuilder` and get its legend key.
    ///
    /// Returns an error if the alphabet has been exhausted.
    pub fn add(&mut self, value: &T) -> Result<char, ()> {
        if let Some(&c) = self.seen_values.get(value) {
            return Ok(c);
        }

        for c in (self.prefix_fn)(value).chars().chain(self.alphabet.chars()) {
            if self.legend.contains_key(&c) {
                continue;
            }

            self.legend.insert(c, value.clone());
            self.seen_values.insert(value.clone(), c);
            return Ok(c);
        }
        self.out_of_alphabet = true;
        Err(())
    }
}

#[cfg(test)]
mod test {
    use super::Prefab;
    use euclid::Point2D;

    #[test]
    fn test_from_text() {
        let a = Prefab::from_text_map("
###
#..
##.
#..
");
        let b = Prefab::from_text_hexmap("
    # # #
   # . .
  # # .
 # . .
");

        assert_eq!(a, b);

        assert_eq!(Some(&'#'), a.get(Point2D::new(0, 0)));
        assert_eq!(Some(&'.'), a.get(Point2D::new(1, 1)));
        assert_eq!(Some(&'#'), a.get(Point2D::new(1, 2)));
    }

    /// Remove whitespace differences from text map strings.
    fn normalize(dirty: &str) -> String {
        // XXX: This should also normalize indetation by removing the longest whitespace prefix
        // shared by every line from each line.

        let mut ret = String::new();
        // Remove trailing whitespace and empty lines.
        let dirty = dirty.trim_right();
        // Remove heading empty lines in iterator construction.
        for line in dirty.lines().skip_while(|line| line.trim() == "") {
            ret.push_str(line.trim_right());
            ret.push('\n');
        }
        ret
    }

    #[test]
    fn test_print() {
        let hex_text = "
      # #
   # . .
  # # . .
 # . .
@ @ @ @";

        let dense_text = "
 ##
#..
##..
#..
@@@@";
        let map = Prefab::from_text_hexmap(&hex_text);

        assert_eq!(normalize(&format!("{}", map.hexmap_display())),
                   normalize(hex_text));
        assert_eq!(normalize(&format!("{}", map)), normalize(dense_text));
    }

    #[test]
    fn test_left_align() {
        let big_hex = "
                                                           * *
                                                        * * * *
                                                     * * * * * *
                                                  * * * * * * * *
                                               * * * * * * * * * *
                                            * * * * * * * * * * * *
                                         * * * * * * * * * * * * * *
                                      * * * * * * * * * * * * * * * *
                                   * * * * * * * * * * * * * * * * * *
                                * * * * * * * * * * * * * * * * * * * *
                             * * * * * * * * * * * * * * * * * * * * * *
                          * * * * * * * * * * * * * * * * * * * * * * * *
                       * * * * * * * * * * * * * * ^ * * * * * * * * * * *
                    * * * * * * * * * * * * * * * * * * * * * * * * * * * *
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
              * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
           * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * , , % # # , , , * * * * * * * * * * * * * *
  * * * * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * * * *
   * * * * * * * * * * * * * * * * * * , , , * * , , , * * * * * * * * * * * * * *
    * * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * * *
     * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * *
      * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * *
       * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * *
        * * * * * * * * * * * * * , , , , , , , , * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * *
          * * * * * * * * * * * * * * * * * * * * * * * * * *
           * * * * * * * * * * * * * * * * * * * * * * * *
            * * * * * * * * * * * * * * * * * * * * * *
             * * * * * * * * * * * * * * * * * * * *
              * * * * * * * * * * * * * * * * * *
               * * * * * * * * * * * * * * * *
                * * * * * * * * * * * * * *
                 * * * * * * * * * * * *
                  * * * * * * * * * *
                   * * * * * * * *
                    * * * * * *
                     * * * *
                      * *";
        let map = Prefab::from_text_hexmap(&big_hex);

        let map2 = Prefab::from_text_hexmap(&format!("{}", map.hexmap_display()));
        assert_eq!(map, map2);

        assert_eq!(normalize(&format!("{}", map.hexmap_display())),
                   normalize(big_hex));

    }
}
<commit_msg>Use vectors instead of points in prefab<commit_after>
use euclid::{Vector2D, vec2, Size2D};
use std::cmp::{max, min};
use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map;
use std::fmt;
use std::hash::Hash;
use std::i32;
use std::iter::{FromIterator, IntoIterator};

/// A structure for storing a piece of a grid map.
///
/// All contents are guaranteed to be stored in the rectangle between (0, 0) (inclusive) and `dim`
/// (exclusive).
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Prefab<T> {
    terrain: HashMap<Vector2D<i32>, usize>,
    elements: Vec<T>,
    dim: Size2D<u32>,
}

impl<T: Clone + Eq + Hash> Prefab<T> {
    fn new() -> Prefab<T> {
        Prefab {
            terrain: HashMap::new(),
            elements: Vec::new(),
            dim: Size2D::new(0, 0),
        }
    }

    pub fn get(&self, pos: Vector2D<i32>) -> Option<&T> {
        self.terrain.get(&pos).map(|&idx| &self.elements[idx])
    }

    pub fn map<F: FnMut(T) -> U, U>(self, f: F) -> Prefab<U> {
        Prefab {
            terrain: self.terrain,
            elements: self.elements.into_iter().map(f).collect(),
            dim: self.dim,
        }
    }

    pub fn dim(&self) -> Size2D<u32> { self.dim }

    pub fn iter(&self) -> PrefabIterator<T> {
        PrefabIterator {
            prefab: self,
            iter: self.terrain.iter(),
        }
    }
}

pub struct PrefabIterator<'a, T: 'a> {
    prefab: &'a Prefab<T>,
    iter: hash_map::Iter<'a, Vector2D<i32>, usize>,
}

impl<'a, T: 'a> Iterator for PrefabIterator<'a, T> {
    type Item = (Vector2D<i32>, &'a T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            Some((&pos, &idx)) => Some((pos, &self.prefab.elements[idx])),
            _ => None,
        }
    }
}

impl<T: Clone + Eq + Hash> FromIterator<(Vector2D<i32>, T)> for Prefab<T> {
    fn from_iter<I: IntoIterator<Item = (Vector2D<i32>, T)>>(iter: I) -> Self {
        // List of unique values.
        let mut element_idx: HashMap<T, usize> = HashMap::new();
        let mut ret = Prefab::new();

        let mut min_x = i32::MAX;
        let mut min_y = i32::MAX;

        // Temporary storage before positions have been normalized.
        let mut temp_buffer = Vec::new();

        for (p, e) in iter {
            min_x = min(min_x, p.x);
            min_y = min(min_y, p.y);

            let val = *element_idx
                           .entry(e.clone())
                           .or_insert_with(|| {
                                               ret.elements.push(e);
                                               ret.elements.len() - 1
                                           });

            temp_buffer.push((p, val));
        }

        // Normalization: Snap bounding box to origin.
        let mut max_x = 0;
        let mut max_y = 0;

        for (mut p, e) in temp_buffer {
            p.x -= min_x;
            assert!(p.x >= 0);
            p.y -= min_y;
            assert!(p.y >= 0);

            max_x = max(p.x as u32, max_x);
            max_y = max(p.y as u32, max_y);

            ret.terrain.insert(p, e);
        }

        ret.dim = Size2D::new(max_x + 1, max_y + 1);

        ret
    }
}

impl Prefab<char> {
    fn from_text<F>(map: &str, project: F) -> Prefab<char>
        where F: Fn(usize, usize) -> (i32, i32)
    {
        let mut buf = Vec::new();
        for (y, line) in map.lines().enumerate() {
            for (x, c) in line.chars().enumerate() {
                let (map_x, map_y) = project(x, y);
                if !c.is_whitespace() {
                    buf.push((vec2(map_x, map_y), c));
                }
            }
        }

        Prefab::from_iter(buf.into_iter())
    }

    pub fn from_text_map(map: &str) -> Prefab<char> {
        Prefab::from_text(map, |x, y| (x as i32, y as i32))
    }

    pub fn from_text_hexmap(map: &str) -> Prefab<char> {
        Prefab::from_text(map, |x, y| ((x + y) as i32 / 2, y as i32))
    }
}

impl<T: fmt::Display + Clone + Eq + Hash> fmt::Display for Prefab<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for y in 0..self.dim.height {
            for x in 0..self.dim.width {
                if let Some(c) = self.get(vec2(x as i32, y as i32)) {
                    write!(f, "{}", c)?;
                } else {
                    write!(f, " ")?;
                }
            }
            writeln!(f, "")?;
        }
        Ok(())
    }
}

impl<T: fmt::Display + Clone + Eq + Hash> Prefab<T> {
    /// Return a wrapper for printing the map in hex layout.
    ///
    /// Without the wrapper the print format will be a traditional dense text map.
    pub fn hexmap_display(&self) -> HexmapDisplay<T> { HexmapDisplay(self) }
}

/// Wrapper type for displaying the `Prefab` as a text hexmap.
pub struct HexmapDisplay<'a, T: 'a>(&'a Prefab<T>);

impl<'a, T: fmt::Display + Clone + Eq + Hash> fmt::Display for HexmapDisplay<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let max_width = (self.0.dim.width * 2 + self.0.dim.height) as i32;

        // Find the smallest displayed x-coordinate that actually shows up in the map.
        let min_x = (0..self.0.dim.width)
            .flat_map(move |x| {
                          (0..self.0.dim.height).map(move |y| vec2(x as i32, y as i32))
                      })
            .filter(|&p| self.0.get(p).is_some())
            .map(|p| p.x * 2 - p.y)
            .min()
            .unwrap_or(0);

        for y in 0..(self.0.dim.height as i32) {
            for x in min_x..(min_x + max_width) {
                if (x - y) % 2 != 0 {
                    write!(f, " ")?;
                    continue;
                }
                let map_x = (x + y) / 2;
                let map_y = y;
                if let Some(c) = self.0.get(vec2(map_x, map_y)) {
                    write!(f, "{}", c)?;
                } else {
                    write!(f, " ")?;
                }
            }
            writeln!(f, "")?;
        }
        Ok(())
    }
}

/// Build a text map legend given an alphabet and a sequence of elements.
///
/// Each unique element will be assigned a letter from the alphabet. A preference function can
/// provide an additional alphabet prefix for specific values, which will be sampled before the
/// main alphabet. This will allow having standard special characters for eg. certain types of
/// terrain tiles. When no special alphabet is required, the preference function can return an
/// empty string.
pub struct LegendBuilder<T, F> {
    /// The generated legend map.
    pub legend: BTreeMap<char, T>,
    /// Set to true if an add operation failed to assign a symbol.
    pub out_of_alphabet: bool,
    seen_values: BTreeMap<T, char>,
    prefix_fn: F,
    alphabet: String,
}

impl<T, F> LegendBuilder<T, F>
    where T: Ord + Eq + Clone,
          F: FnMut(&T) -> &'static str
{
    /// Initialize the legend builder.
    pub fn new(alphabet: String, prefix_fn: F) -> LegendBuilder<T, F> {
        LegendBuilder {
            legend: BTreeMap::new(),
            out_of_alphabet: false,
            seen_values: BTreeMap::new(),
            prefix_fn: prefix_fn,
            alphabet: alphabet,
        }
    }

    /// Show a value to `LegendBuilder` and get its legend key.
    ///
    /// Returns an error if the alphabet has been exhausted.
    pub fn add(&mut self, value: &T) -> Result<char, ()> {
        if let Some(&c) = self.seen_values.get(value) {
            return Ok(c);
        }

        for c in (self.prefix_fn)(value).chars().chain(self.alphabet.chars()) {
            if self.legend.contains_key(&c) {
                continue;
            }

            self.legend.insert(c, value.clone());
            self.seen_values.insert(value.clone(), c);
            return Ok(c);
        }
        self.out_of_alphabet = true;
        Err(())
    }
}

#[cfg(test)]
mod test {
    use super::Prefab;
    use euclid::vec2;

    #[test]
    fn test_from_text() {
        let a = Prefab::from_text_map("
###
#..
##.
#..
");
        let b = Prefab::from_text_hexmap("
    # # #
   # . .
  # # .
 # . .
");

        assert_eq!(a, b);

        assert_eq!(Some(&'#'), a.get(vec2(0, 0)));
        assert_eq!(Some(&'.'), a.get(vec2(1, 1)));
        assert_eq!(Some(&'#'), a.get(vec2(1, 2)));
    }

    /// Remove whitespace differences from text map strings.
    fn normalize(dirty: &str) -> String {
        // XXX: This should also normalize indetation by removing the longest whitespace prefix
        // shared by every line from each line.

        let mut ret = String::new();
        // Remove trailing whitespace and empty lines.
        let dirty = dirty.trim_right();
        // Remove heading empty lines in iterator construction.
        for line in dirty.lines().skip_while(|line| line.trim() == "") {
            ret.push_str(line.trim_right());
            ret.push('\n');
        }
        ret
    }

    #[test]
    fn test_print() {
        let hex_text = "
      # #
   # . .
  # # . .
 # . .
@ @ @ @";

        let dense_text = "
 ##
#..
##..
#..
@@@@";
        let map = Prefab::from_text_hexmap(&hex_text);

        assert_eq!(normalize(&format!("{}", map.hexmap_display())),
                   normalize(hex_text));
        assert_eq!(normalize(&format!("{}", map)), normalize(dense_text));
    }

    #[test]
    fn test_left_align() {
        let big_hex = "
                                                           * *
                                                        * * * *
                                                     * * * * * *
                                                  * * * * * * * *
                                               * * * * * * * * * *
                                            * * * * * * * * * * * *
                                         * * * * * * * * * * * * * *
                                      * * * * * * * * * * * * * * * *
                                   * * * * * * * * * * * * * * * * * *
                                * * * * * * * * * * * * * * * * * * * *
                             * * * * * * * * * * * * * * * * * * * * * *
                          * * * * * * * * * * * * * * * * * * * * * * * *
                       * * * * * * * * * * * * * * ^ * * * * * * * * * * *
                    * * * * * * * * * * * * * * * * * * * * * * * * * * * *
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
              * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
           * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * , , % # # , , , * * * * * * * * * * * * * *
  * * * * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * * * *
   * * * * * * * * * * * * * * * * * * , , , * * , , , * * * * * * * * * * * * * *
    * * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * * *
     * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * *
      * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * *
       * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * *
        * * * * * * * * * * * * * , , , , , , , , * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * *
          * * * * * * * * * * * * * * * * * * * * * * * * * *
           * * * * * * * * * * * * * * * * * * * * * * * *
            * * * * * * * * * * * * * * * * * * * * * *
             * * * * * * * * * * * * * * * * * * * *
              * * * * * * * * * * * * * * * * * *
               * * * * * * * * * * * * * * * *
                * * * * * * * * * * * * * *
                 * * * * * * * * * * * *
                  * * * * * * * * * *
                   * * * * * * * *
                    * * * * * *
                     * * * *
                      * *";
        let map = Prefab::from_text_hexmap(&big_hex);

        let map2 = Prefab::from_text_hexmap(&format!("{}", map.hexmap_display()));
        assert_eq!(map, map2);

        assert_eq!(normalize(&format!("{}", map.hexmap_display())),
                   normalize(big_hex));

    }
}
<|endoftext|>


<commit_before>//! Constructs the dependency graph for compilation.
//!
//! Rust code is typically organized as a set of Cargo packages. The
//! dependencies between the packages themselves are stored in the
//! `Resolve` struct. However, we can't use that information as is for
//! compilation! A package typically contains several targets, or crates,
//! and these targets has inter-dependencies. For example, you need to
//! compile the `lib` target before the `bin` one, and you need to compile
//! `build.rs` before either of those.
//!
//! So, we need to lower the `Resolve`, which specifies dependencies between
//! *packages*, to a graph of dependencies between their *targets*, and this
//! is exactly what this module is doing! Well, almost exactly: another
//! complication is that we might want to compile the same target several times
//! (for example, with and without tests), so we actually build a dependency
//! graph of `Unit`s, which capture these properties.

use super::{BuildContext, CompileMode, Kind, Unit};
use core::dependency::Kind as DepKind;
use core::profiles::ProfileFor;
use core::{Package, Target};
use std::collections::HashMap;
use CargoResult;

pub fn build_unit_dependencies<'a, 'cfg>(
    roots: &[Unit<'a>],
    bcx: &BuildContext<'a, 'cfg>,
    mut deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
) -> CargoResult<()> {
    for unit in roots.iter() {
        // Dependencies of tests/benches should not have `panic` set.
        // We check the global test mode to see if we are running in `cargo
        // test` in which case we ensure all dependencies have `panic`
        // cleared, and avoid building the lib thrice (once with `panic`, once
        // without, once for --test).  In particular, the lib included for
        // doctests and examples are `Build` mode here.
        let profile_for = if unit.mode.is_any_test() || bcx.build_config.test() {
            ProfileFor::TestDependency
        } else {
            ProfileFor::Any
        };
        deps_of(unit, bcx, &mut deps, profile_for)?;
    }

    Ok(())
}

fn deps_of<'a, 'b, 'cfg>(
    unit: &Unit<'a>,
    bcx: &BuildContext<'a, 'cfg>,
    deps: &'b mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
    profile_for: ProfileFor,
) -> CargoResult<&'b [Unit<'a>]> {
    // Currently the `deps` map does not include `profile_for`.  This should
    // be safe for now.  `TestDependency` only exists to clear the `panic`
    // flag, and you'll never ask for a `unit` with `panic` set as a
    // `TestDependency`.  `CustomBuild` should also be fine since if the
    // requested unit's settings are the same as `Any`, `CustomBuild` can't
    // affect anything else in the hierarchy.
    if !deps.contains_key(unit) {
        let unit_deps = compute_deps(unit, bcx, deps, profile_for)?;
        let to_insert: Vec<_> = unit_deps.iter().map(|&(unit, _)| unit).collect();
        deps.insert(*unit, to_insert);
        for (unit, profile_for) in unit_deps {
            deps_of(&unit, bcx, deps, profile_for)?;
        }
    }
    Ok(deps[unit].as_ref())
}

/// For a package, return all targets which are registered as dependencies
/// for that package.
/// This returns a vec of `(Unit, ProfileFor)` pairs.  The `ProfileFor`
/// is the profile type that should be used for dependencies of the unit.
fn compute_deps<'a, 'b, 'cfg>(
    unit: &Unit<'a>,
    bcx: &BuildContext<'a, 'cfg>,
    deps: &'b mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
    profile_for: ProfileFor,
) -> CargoResult<Vec<(Unit<'a>, ProfileFor)>> {
    if unit.mode.is_run_custom_build() {
        return compute_deps_custom_build(unit, bcx, deps);
    } else if unit.mode.is_doc() && !unit.mode.is_any_test() {
        // Note: This does not include Doctest.
        return compute_deps_doc(unit, bcx);
    }

    let id = unit.pkg.package_id();
    let deps = bcx.resolve.deps(id);
    let mut ret = deps.filter(|&(_id, deps)| {
        assert!(deps.len() > 0);
        deps.iter().any(|dep| {
            // If this target is a build command, then we only want build
            // dependencies, otherwise we want everything *other than* build
            // dependencies.
            if unit.target.is_custom_build() != dep.is_build() {
                return false;
            }

            // If this dependency is *not* a transitive dependency, then it
            // only applies to test/example targets
            if !dep.is_transitive() && !unit.target.is_test() && !unit.target.is_example()
                && !unit.mode.is_any_test()
            {
                return false;
            }

            // If this dependency is only available for certain platforms,
            // make sure we're only enabling it for that platform.
            if !bcx.dep_platform_activated(dep, unit.kind) {
                return false;
            }

            // If the dependency is optional, then we're only activating it
            // if the corresponding feature was activated
            if dep.is_optional() && !bcx.resolve.features(id).contains(&*dep.name()) {
                return false;
            }

            // If we've gotten past all that, then this dependency is
            // actually used!
            true
        })
    }).filter_map(|(id, _)| match bcx.get_package(id) {
            Ok(pkg) => pkg.targets().iter().find(|t| t.is_lib()).map(|t| {
                let mode = check_or_build_mode(&unit.mode, t);
                let unit = new_unit(bcx, pkg, t, profile_for, unit.kind.for_target(t), mode);
                Ok((unit, profile_for))
            }),
            Err(e) => Some(Err(e)),
        })
        .collect::<CargoResult<Vec<_>>>()?;

    // If this target is a build script, then what we've collected so far is
    // all we need. If this isn't a build script, then it depends on the
    // build script if there is one.
    if unit.target.is_custom_build() {
        return Ok(ret);
    }
    ret.extend(dep_build_script(unit, bcx));

    // If this target is a binary, test, example, etc, then it depends on
    // the library of the same package. The call to `resolve.deps` above
    // didn't include `pkg` in the return values, so we need to special case
    // it here and see if we need to push `(pkg, pkg_lib_target)`.
    if unit.target.is_lib() && unit.mode != CompileMode::Doctest {
        return Ok(ret);
    }
    ret.extend(maybe_lib(unit, bcx, profile_for));

    // If any integration tests/benches are being run, make sure that
    // binaries are built as well.
    if !unit.mode.is_check() && unit.mode.is_any_test()
        && (unit.target.is_test() || unit.target.is_bench())
    {
        ret.extend(
            unit.pkg
                .targets()
                .iter()
                .filter(|t| {
                    let no_required_features = Vec::new();

                    t.is_bin() &&
                        // Skip binaries with required features that have not been selected.
                        t.required_features().unwrap_or(&no_required_features).iter().all(|f| {
                            bcx.resolve.features(id).contains(f)
                        })
                })
                .map(|t| {
                    (
                        new_unit(
                            bcx,
                            unit.pkg,
                            t,
                            ProfileFor::Any,
                            unit.kind.for_target(t),
                            CompileMode::Build,
                        ),
                        ProfileFor::Any,
                    )
                }),
        );
    }

    Ok(ret)
}

/// Returns the dependencies needed to run a build script.
///
/// The `unit` provided must represent an execution of a build script, and
/// the returned set of units must all be run before `unit` is run.
fn compute_deps_custom_build<'a, 'cfg>(
    unit: &Unit<'a>,
    bcx: &BuildContext<'a, 'cfg>,
    deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
) -> CargoResult<Vec<(Unit<'a>, ProfileFor)>> {
    // When not overridden, then the dependencies to run a build script are:
    //
    // 1. Compiling the build script itself
    // 2. For each immediate dependency of our package which has a `links`
    //    key, the execution of that build script.
    let not_custom_build = unit.pkg
        .targets()
        .iter()
        .find(|t| !t.is_custom_build())
        .unwrap();
    let tmp = Unit {
        pkg: unit.pkg,
        target: not_custom_build,
        profile: unit.profile,
        kind: unit.kind,
        mode: CompileMode::Build,
    };
    let deps = deps_of(&tmp, bcx, deps, ProfileFor::Any)?;
    Ok(deps.iter()
        .filter_map(|unit| {
            if !unit.target.linkable() || unit.pkg.manifest().links().is_none() {
                return None;
            }
            dep_build_script(unit, bcx)
        })
        .chain(Some((
            new_unit(
                bcx,
                unit.pkg,
                unit.target,
                ProfileFor::CustomBuild,
                Kind::Host, // build scripts always compiled for the host
                CompileMode::Build,
            ),
            // All dependencies of this unit should use profiles for custom
            // builds.
            ProfileFor::CustomBuild,
        )))
        .collect())
}

/// Returns the dependencies necessary to document a package
fn compute_deps_doc<'a, 'cfg>(
    unit: &Unit<'a>,
    bcx: &BuildContext<'a, 'cfg>,
) -> CargoResult<Vec<(Unit<'a>, ProfileFor)>> {
    let deps = bcx.resolve
        .deps(unit.pkg.package_id())
        .filter(|&(_id, deps)| {
            deps.iter().any(|dep| match dep.kind() {
                DepKind::Normal => bcx.dep_platform_activated(dep, unit.kind),
                _ => false,
            })
        })
        .map(|(id, _deps)| bcx.get_package(id));

    // To document a library, we depend on dependencies actually being
    // built. If we're documenting *all* libraries, then we also depend on
    // the documentation of the library being built.
    let mut ret = Vec::new();
    for dep in deps {
        let dep = dep?;
        let lib = match dep.targets().iter().find(|t| t.is_lib()) {
            Some(lib) => lib,
            None => continue,
        };
        // rustdoc only needs rmeta files for regular dependencies.
        // However, for plugins/proc-macros, deps should be built like normal.
        let mode = check_or_build_mode(&unit.mode, lib);
        let lib_unit = new_unit(
            bcx,
            dep,
            lib,
            ProfileFor::Any,
            unit.kind.for_target(lib),
            mode,
        );
        ret.push((lib_unit, ProfileFor::Any));
        if let CompileMode::Doc { deps: true } = unit.mode {
            // Document this lib as well.
            let doc_unit = new_unit(
                bcx,
                dep,
                lib,
                ProfileFor::Any,
                unit.kind.for_target(lib),
                unit.mode,
            );
            ret.push((doc_unit, ProfileFor::Any));
        }
    }

    // Be sure to build/run the build script for documented libraries as
    ret.extend(dep_build_script(unit, bcx));

    // If we document a binary, we need the library available
    if unit.target.is_bin() {
        ret.extend(maybe_lib(unit, bcx, ProfileFor::Any));
    }
    Ok(ret)
}

fn maybe_lib<'a>(
    unit: &Unit<'a>,
    bcx: &BuildContext,
    profile_for: ProfileFor,
) -> Option<(Unit<'a>, ProfileFor)> {
    unit.pkg.targets().iter().find(|t| t.linkable()).map(|t| {
        let mode = check_or_build_mode(&unit.mode, t);
        let unit = new_unit(bcx, unit.pkg, t, profile_for, unit.kind.for_target(t), mode);
        (unit, profile_for)
    })
}

/// If a build script is scheduled to be run for the package specified by
/// `unit`, this function will return the unit to run that build script.
///
/// Overriding a build script simply means that the running of the build
/// script itself doesn't have any dependencies, so even in that case a unit
/// of work is still returned. `None` is only returned if the package has no
/// build script.
fn dep_build_script<'a>(unit: &Unit<'a>, bcx: &BuildContext) -> Option<(Unit<'a>, ProfileFor)> {
    unit.pkg
        .targets()
        .iter()
        .find(|t| t.is_custom_build())
        .map(|t| {
            // The profile stored in the Unit is the profile for the thing
            // the custom build script is running for.
            (
                Unit {
                    pkg: unit.pkg,
                    target: t,
                    profile: bcx.profiles.get_profile_run_custom_build(&unit.profile),
                    kind: unit.kind,
                    mode: CompileMode::RunCustomBuild,
                },
                ProfileFor::CustomBuild,
            )
        })
}

/// Choose the correct mode for dependencies.
fn check_or_build_mode(mode: &CompileMode, target: &Target) -> CompileMode {
    match *mode {
        CompileMode::Check { .. } | CompileMode::Doc { .. } => {
            if target.for_host() {
                // Plugin and proc-macro targets should be compiled like
                // normal.
                CompileMode::Build
            } else {
                // Regular dependencies should not be checked with --test.
                // Regular dependencies of doc targets should emit rmeta only.
                CompileMode::Check { test: false }
            }
        }
        _ => CompileMode::Build,
    }
}

fn new_unit<'a>(
    bcx: &BuildContext,
    pkg: &'a Package,
    target: &'a Target,
    profile_for: ProfileFor,
    kind: Kind,
    mode: CompileMode,
) -> Unit<'a> {
    let profile = bcx.profiles.get_profile(
        &pkg.package_id(),
        bcx.ws.is_member(pkg),
        profile_for,
        mode,
        bcx.build_config.release,
    );
    Unit {
        pkg,
        target,
        profile,
        kind,
        mode,
    }
}
<commit_msg>Don't pollute the deps_map.<commit_after>//! Constructs the dependency graph for compilation.
//!
//! Rust code is typically organized as a set of Cargo packages. The
//! dependencies between the packages themselves are stored in the
//! `Resolve` struct. However, we can't use that information as is for
//! compilation! A package typically contains several targets, or crates,
//! and these targets has inter-dependencies. For example, you need to
//! compile the `lib` target before the `bin` one, and you need to compile
//! `build.rs` before either of those.
//!
//! So, we need to lower the `Resolve`, which specifies dependencies between
//! *packages*, to a graph of dependencies between their *targets*, and this
//! is exactly what this module is doing! Well, almost exactly: another
//! complication is that we might want to compile the same target several times
//! (for example, with and without tests), so we actually build a dependency
//! graph of `Unit`s, which capture these properties.

use super::{BuildContext, CompileMode, Kind, Unit};
use core::dependency::Kind as DepKind;
use core::profiles::ProfileFor;
use core::{Package, Target};
use std::collections::HashMap;
use CargoResult;

pub fn build_unit_dependencies<'a, 'cfg>(
    roots: &[Unit<'a>],
    bcx: &BuildContext<'a, 'cfg>,
    mut deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
) -> CargoResult<()> {
    for unit in roots.iter() {
        // Dependencies of tests/benches should not have `panic` set.
        // We check the global test mode to see if we are running in `cargo
        // test` in which case we ensure all dependencies have `panic`
        // cleared, and avoid building the lib thrice (once with `panic`, once
        // without, once for --test).  In particular, the lib included for
        // doctests and examples are `Build` mode here.
        let profile_for = if unit.mode.is_any_test() || bcx.build_config.test() {
            ProfileFor::TestDependency
        } else {
            ProfileFor::Any
        };
        deps_of(unit, bcx, &mut deps, profile_for)?;
    }

    Ok(())
}

fn deps_of<'a, 'b, 'cfg>(
    unit: &Unit<'a>,
    bcx: &BuildContext<'a, 'cfg>,
    deps: &'b mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
    profile_for: ProfileFor,
) -> CargoResult<&'b [Unit<'a>]> {
    // Currently the `deps` map does not include `profile_for`.  This should
    // be safe for now.  `TestDependency` only exists to clear the `panic`
    // flag, and you'll never ask for a `unit` with `panic` set as a
    // `TestDependency`.  `CustomBuild` should also be fine since if the
    // requested unit's settings are the same as `Any`, `CustomBuild` can't
    // affect anything else in the hierarchy.
    if !deps.contains_key(unit) {
        let unit_deps = compute_deps(unit, bcx, deps, profile_for)?;
        let to_insert: Vec<_> = unit_deps.iter().map(|&(unit, _)| unit).collect();
        deps.insert(*unit, to_insert);
        for (unit, profile_for) in unit_deps {
            deps_of(&unit, bcx, deps, profile_for)?;
        }
    }
    Ok(deps[unit].as_ref())
}

/// For a package, return all targets which are registered as dependencies
/// for that package.
/// This returns a vec of `(Unit, ProfileFor)` pairs.  The `ProfileFor`
/// is the profile type that should be used for dependencies of the unit.
fn compute_deps<'a, 'b, 'cfg>(
    unit: &Unit<'a>,
    bcx: &BuildContext<'a, 'cfg>,
    deps: &'b mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
    profile_for: ProfileFor,
) -> CargoResult<Vec<(Unit<'a>, ProfileFor)>> {
    if unit.mode.is_run_custom_build() {
        return compute_deps_custom_build(unit, bcx, deps);
    } else if unit.mode.is_doc() && !unit.mode.is_any_test() {
        // Note: This does not include Doctest.
        return compute_deps_doc(unit, bcx);
    }

    let id = unit.pkg.package_id();
    let deps = bcx.resolve.deps(id);
    let mut ret = deps.filter(|&(_id, deps)| {
        assert!(deps.len() > 0);
        deps.iter().any(|dep| {
            // If this target is a build command, then we only want build
            // dependencies, otherwise we want everything *other than* build
            // dependencies.
            if unit.target.is_custom_build() != dep.is_build() {
                return false;
            }

            // If this dependency is *not* a transitive dependency, then it
            // only applies to test/example targets
            if !dep.is_transitive() && !unit.target.is_test() && !unit.target.is_example()
                && !unit.mode.is_any_test()
            {
                return false;
            }

            // If this dependency is only available for certain platforms,
            // make sure we're only enabling it for that platform.
            if !bcx.dep_platform_activated(dep, unit.kind) {
                return false;
            }

            // If the dependency is optional, then we're only activating it
            // if the corresponding feature was activated
            if dep.is_optional() && !bcx.resolve.features(id).contains(&*dep.name()) {
                return false;
            }

            // If we've gotten past all that, then this dependency is
            // actually used!
            true
        })
    }).filter_map(|(id, _)| match bcx.get_package(id) {
            Ok(pkg) => pkg.targets().iter().find(|t| t.is_lib()).map(|t| {
                let mode = check_or_build_mode(&unit.mode, t);
                let unit = new_unit(bcx, pkg, t, profile_for, unit.kind.for_target(t), mode);
                Ok((unit, profile_for))
            }),
            Err(e) => Some(Err(e)),
        })
        .collect::<CargoResult<Vec<_>>>()?;

    // If this target is a build script, then what we've collected so far is
    // all we need. If this isn't a build script, then it depends on the
    // build script if there is one.
    if unit.target.is_custom_build() {
        return Ok(ret);
    }
    ret.extend(dep_build_script(unit, bcx));

    // If this target is a binary, test, example, etc, then it depends on
    // the library of the same package. The call to `resolve.deps` above
    // didn't include `pkg` in the return values, so we need to special case
    // it here and see if we need to push `(pkg, pkg_lib_target)`.
    if unit.target.is_lib() && unit.mode != CompileMode::Doctest {
        return Ok(ret);
    }
    ret.extend(maybe_lib(unit, bcx, profile_for));

    // If any integration tests/benches are being run, make sure that
    // binaries are built as well.
    if !unit.mode.is_check() && unit.mode.is_any_test()
        && (unit.target.is_test() || unit.target.is_bench())
    {
        ret.extend(
            unit.pkg
                .targets()
                .iter()
                .filter(|t| {
                    let no_required_features = Vec::new();

                    t.is_bin() &&
                        // Skip binaries with required features that have not been selected.
                        t.required_features().unwrap_or(&no_required_features).iter().all(|f| {
                            bcx.resolve.features(id).contains(f)
                        })
                })
                .map(|t| {
                    (
                        new_unit(
                            bcx,
                            unit.pkg,
                            t,
                            ProfileFor::Any,
                            unit.kind.for_target(t),
                            CompileMode::Build,
                        ),
                        ProfileFor::Any,
                    )
                }),
        );
    }

    Ok(ret)
}

/// Returns the dependencies needed to run a build script.
///
/// The `unit` provided must represent an execution of a build script, and
/// the returned set of units must all be run before `unit` is run.
fn compute_deps_custom_build<'a, 'cfg>(
    unit: &Unit<'a>,
    bcx: &BuildContext<'a, 'cfg>,
    deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
) -> CargoResult<Vec<(Unit<'a>, ProfileFor)>> {
    // When not overridden, then the dependencies to run a build script are:
    //
    // 1. Compiling the build script itself
    // 2. For each immediate dependency of our package which has a `links`
    //    key, the execution of that build script.
    let deps = deps
        .iter()
        .find(|(key, _deps)| key.pkg == unit.pkg && !key.target.is_custom_build())
        .expect("can't find package deps")
        .1;
    Ok(deps.iter()
        .filter_map(|unit| {
            if !unit.target.linkable() || unit.pkg.manifest().links().is_none() {
                return None;
            }
            dep_build_script(unit, bcx)
        })
        .chain(Some((
            new_unit(
                bcx,
                unit.pkg,
                unit.target,
                ProfileFor::CustomBuild,
                Kind::Host, // build scripts always compiled for the host
                CompileMode::Build,
            ),
            // All dependencies of this unit should use profiles for custom
            // builds.
            ProfileFor::CustomBuild,
        )))
        .collect())
}

/// Returns the dependencies necessary to document a package
fn compute_deps_doc<'a, 'cfg>(
    unit: &Unit<'a>,
    bcx: &BuildContext<'a, 'cfg>,
) -> CargoResult<Vec<(Unit<'a>, ProfileFor)>> {
    let deps = bcx.resolve
        .deps(unit.pkg.package_id())
        .filter(|&(_id, deps)| {
            deps.iter().any(|dep| match dep.kind() {
                DepKind::Normal => bcx.dep_platform_activated(dep, unit.kind),
                _ => false,
            })
        })
        .map(|(id, _deps)| bcx.get_package(id));

    // To document a library, we depend on dependencies actually being
    // built. If we're documenting *all* libraries, then we also depend on
    // the documentation of the library being built.
    let mut ret = Vec::new();
    for dep in deps {
        let dep = dep?;
        let lib = match dep.targets().iter().find(|t| t.is_lib()) {
            Some(lib) => lib,
            None => continue,
        };
        // rustdoc only needs rmeta files for regular dependencies.
        // However, for plugins/proc-macros, deps should be built like normal.
        let mode = check_or_build_mode(&unit.mode, lib);
        let lib_unit = new_unit(
            bcx,
            dep,
            lib,
            ProfileFor::Any,
            unit.kind.for_target(lib),
            mode,
        );
        ret.push((lib_unit, ProfileFor::Any));
        if let CompileMode::Doc { deps: true } = unit.mode {
            // Document this lib as well.
            let doc_unit = new_unit(
                bcx,
                dep,
                lib,
                ProfileFor::Any,
                unit.kind.for_target(lib),
                unit.mode,
            );
            ret.push((doc_unit, ProfileFor::Any));
        }
    }

    // Be sure to build/run the build script for documented libraries as
    ret.extend(dep_build_script(unit, bcx));

    // If we document a binary, we need the library available
    if unit.target.is_bin() {
        ret.extend(maybe_lib(unit, bcx, ProfileFor::Any));
    }
    Ok(ret)
}

fn maybe_lib<'a>(
    unit: &Unit<'a>,
    bcx: &BuildContext,
    profile_for: ProfileFor,
) -> Option<(Unit<'a>, ProfileFor)> {
    unit.pkg.targets().iter().find(|t| t.linkable()).map(|t| {
        let mode = check_or_build_mode(&unit.mode, t);
        let unit = new_unit(bcx, unit.pkg, t, profile_for, unit.kind.for_target(t), mode);
        (unit, profile_for)
    })
}

/// If a build script is scheduled to be run for the package specified by
/// `unit`, this function will return the unit to run that build script.
///
/// Overriding a build script simply means that the running of the build
/// script itself doesn't have any dependencies, so even in that case a unit
/// of work is still returned. `None` is only returned if the package has no
/// build script.
fn dep_build_script<'a>(unit: &Unit<'a>, bcx: &BuildContext) -> Option<(Unit<'a>, ProfileFor)> {
    unit.pkg
        .targets()
        .iter()
        .find(|t| t.is_custom_build())
        .map(|t| {
            // The profile stored in the Unit is the profile for the thing
            // the custom build script is running for.
            (
                Unit {
                    pkg: unit.pkg,
                    target: t,
                    profile: bcx.profiles.get_profile_run_custom_build(&unit.profile),
                    kind: unit.kind,
                    mode: CompileMode::RunCustomBuild,
                },
                ProfileFor::CustomBuild,
            )
        })
}

/// Choose the correct mode for dependencies.
fn check_or_build_mode(mode: &CompileMode, target: &Target) -> CompileMode {
    match *mode {
        CompileMode::Check { .. } | CompileMode::Doc { .. } => {
            if target.for_host() {
                // Plugin and proc-macro targets should be compiled like
                // normal.
                CompileMode::Build
            } else {
                // Regular dependencies should not be checked with --test.
                // Regular dependencies of doc targets should emit rmeta only.
                CompileMode::Check { test: false }
            }
        }
        _ => CompileMode::Build,
    }
}

fn new_unit<'a>(
    bcx: &BuildContext,
    pkg: &'a Package,
    target: &'a Target,
    profile_for: ProfileFor,
    kind: Kind,
    mode: CompileMode,
) -> Unit<'a> {
    let profile = bcx.profiles.get_profile(
        &pkg.package_id(),
        bcx.ws.is_member(pkg),
        profile_for,
        mode,
        bcx.build_config.release,
    );
    Unit {
        pkg,
        target,
        profile,
        kind,
        mode,
    }
}
<|endoftext|>