<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/.
 */

extern crate numeral;

use numeral::Numeral;
use std::fs::File;
use std::io::{BufRead, BufReader, Write};

macro_rules! test_call_on_min_max {
    ($fn_name: ident, $numtype: ty) => (
        #[test]
        fn $fn_name() {
            <$numtype>::max_value().ordinal();
            <$numtype>::min_value().ordinal();
        }
    )
}

test_call_on_min_max!(call_on_min_max_i8, i8);
test_call_on_min_max!(call_on_min_max_u8, u8);
test_call_on_min_max!(call_on_min_max_i16, i16);
test_call_on_min_max!(call_on_min_max_u16, u16);
test_call_on_min_max!(call_on_min_max_i32, i32);
test_call_on_min_max!(call_on_min_max_u32, u32);
test_call_on_min_max!(call_on_min_max_i64, i64);
test_call_on_min_max!(call_on_min_max_u64, u64);

macro_rules! test_call_on_range {
    ($fn_name: ident, $numtype: ty) => {
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..(<$numtype>::max_value()) {
                n.ordinal();
            }
            // waiting for inclusive ranges
            <$numtype>::max_value().ordinal();
        }
    }
}

test_call_on_range!(call_on_range_i8, i8);
test_call_on_range!(call_on_range_u8, u8);
test_call_on_range!(call_on_range_i16, i16);
test_call_on_range!(call_on_range_u16, u16);

macro_rules! test_call_on_critical_ranges {
    ($fn_name: ident, $numtype: ty) => (
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..(<$numtype>::min_value()) + 130 {
                n.ordinal();
            }
            for n in (<$numtype>::max_value()) - 130..(<$numtype>::max_value()) {
                n.ordinal();
            }
            // waiting for inclusive ranges
            <$numtype>::max_value().ordinal();
            if <$numtype>::min_value() != 0 {
                for n in -130..130 {
                    n.ordinal();
                }
            }
        }
    )
}

test_call_on_critical_ranges!(call_on_critical_ranges_i32, i32);
test_call_on_critical_ranges!(call_on_critical_ranges_u32, u32);
test_call_on_critical_ranges!(call_on_critical_ranges_i64, i64);
test_call_on_critical_ranges!(call_on_critical_ranges_u64, u64);

#[test]
fn ordinal_int_m256_257() {
    let file = File::open("tests/ordinal_m256..257.txt").unwrap();
    assert!(BufReader::new(file).lines()
            .map(|n| n.unwrap())
            .eq((-256..257).map(|n| n.ordinal())));
}

#[test]
fn ordinal_int_min_max() {
    let file = File::open("tests/ordinal_min_max.txt").unwrap();
    let mut lines = BufReader::new(file).lines().map(|l| l.unwrap());
    macro_rules! assert_eq_min_max {
        ($signed: ty, $unsigned: ty) => {
            assert_eq!(lines.next().unwrap(), <$signed>::min_value().ordinal());
            assert_eq!(lines.next().unwrap(), <$signed>::max_value().ordinal());
            assert_eq!(lines.next().unwrap(), <$unsigned>::max_value().ordinal());
        }
    }
    assert_eq!(lines.next().unwrap(), 0.ordinal());
    assert_eq_min_max!(i8, u8);
    assert_eq_min_max!(i16, u16);
    assert_eq_min_max!(i32, u32);
    assert_eq_min_max!(i64, u64);
}
<commit_msg>remove unused import<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/.
 */

extern crate numeral;

use numeral::Numeral;
use std::fs::File;
use std::io::{BufRead, BufReader};

macro_rules! test_call_on_min_max {
    ($fn_name: ident, $numtype: ty) => (
        #[test]
        fn $fn_name() {
            <$numtype>::max_value().ordinal();
            <$numtype>::min_value().ordinal();
        }
    )
}

test_call_on_min_max!(call_on_min_max_i8, i8);
test_call_on_min_max!(call_on_min_max_u8, u8);
test_call_on_min_max!(call_on_min_max_i16, i16);
test_call_on_min_max!(call_on_min_max_u16, u16);
test_call_on_min_max!(call_on_min_max_i32, i32);
test_call_on_min_max!(call_on_min_max_u32, u32);
test_call_on_min_max!(call_on_min_max_i64, i64);
test_call_on_min_max!(call_on_min_max_u64, u64);

macro_rules! test_call_on_range {
    ($fn_name: ident, $numtype: ty) => {
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..(<$numtype>::max_value()) {
                n.ordinal();
            }
            // waiting for inclusive ranges
            <$numtype>::max_value().ordinal();
        }
    }
}

test_call_on_range!(call_on_range_i8, i8);
test_call_on_range!(call_on_range_u8, u8);
test_call_on_range!(call_on_range_i16, i16);
test_call_on_range!(call_on_range_u16, u16);

macro_rules! test_call_on_critical_ranges {
    ($fn_name: ident, $numtype: ty) => (
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..(<$numtype>::min_value()) + 130 {
                n.ordinal();
            }
            for n in (<$numtype>::max_value()) - 130..(<$numtype>::max_value()) {
                n.ordinal();
            }
            // waiting for inclusive ranges
            <$numtype>::max_value().ordinal();
            if <$numtype>::min_value() != 0 {
                for n in -130..130 {
                    n.ordinal();
                }
            }
        }
    )
}

test_call_on_critical_ranges!(call_on_critical_ranges_i32, i32);
test_call_on_critical_ranges!(call_on_critical_ranges_u32, u32);
test_call_on_critical_ranges!(call_on_critical_ranges_i64, i64);
test_call_on_critical_ranges!(call_on_critical_ranges_u64, u64);

#[test]
fn ordinal_int_m256_257() {
    let file = File::open("tests/ordinal_m256..257.txt").unwrap();
    assert!(BufReader::new(file).lines()
            .map(|n| n.unwrap())
            .eq((-256..257).map(|n| n.ordinal())));
}

#[test]
fn ordinal_int_min_max() {
    let file = File::open("tests/ordinal_min_max.txt").unwrap();
    let mut lines = BufReader::new(file).lines().map(|l| l.unwrap());
    macro_rules! assert_eq_min_max {
        ($signed: ty, $unsigned: ty) => {
            assert_eq!(lines.next().unwrap(), <$signed>::min_value().ordinal());
            assert_eq!(lines.next().unwrap(), <$signed>::max_value().ordinal());
            assert_eq!(lines.next().unwrap(), <$unsigned>::max_value().ordinal());
        }
    }
    assert_eq!(lines.next().unwrap(), 0.ordinal());
    assert_eq_min_max!(i8, u8);
    assert_eq_min_max!(i16, u16);
    assert_eq_min_max!(i32, u32);
    assert_eq_min_max!(i64, u64);
}
<|endoftext|>


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

#[derive(Debug)]
pub struct NiceOutput {
    pub status: i32,
    pub stdout: String,
    pub stderr: String,
}

fn run(args: Vec<&str>) -> NiceOutput {
    let mut directory = env::current_exe().unwrap();
            directory.pop(); // chop off exe name but leave "debug"
    let name = format!("to{}", env::consts::EXE_SUFFIX);
    let binary = directory.join(&name);

    let mut command = Command::new(binary);
            command.args(&args);
    let output = command.output().unwrap();

    return NiceOutput {
        status: output.status.code().unwrap(),
        stdout: String::from_utf8(output.stdout).unwrap().trim(),
        stderr: String::from_utf8(output.stderr).unwrap().trim(),
    };
}

#[test]
fn smoke_test() {
    let result = run(vec!["-h"]);
    assert_eq!(result.status, 0);
}

#[test]
fn version_test() {
    let result = run(vec!["--version"]);
    let version = env!("CARGO_PKG_VERSION");
    let expected = format!("to {}", version);

    assert_eq!(result.stdout, expected);
}
<commit_msg>Fixes type error in tests.<commit_after>use std::env;
use std::process::Command;

#[derive(Debug)]
pub struct NiceOutput {
    pub status: i32,
    pub stdout: String,
    pub stderr: String,
}

fn run(args: Vec<&str>) -> NiceOutput {
    let mut directory = env::current_exe().unwrap();
            directory.pop(); // chop off exe name but leave "debug"
    let name = format!("to{}", env::consts::EXE_SUFFIX);
    let binary = directory.join(&name);

    let mut command = Command::new(binary);
            command.args(&args);
    let output = command.output().unwrap();
    let stdout = trim(output.stdout);
    let stderr = trim(output.stderr);

    return NiceOutput {
        status: output.status.code().unwrap(),
        stdout: stdout,
        stderr: stderr,
    };
}

fn trim(output: Vec<u8>) -> String {
    let string = String::from_utf8(output).unwrap();
    return String::from(string.trim());
}

#[test]
fn smoke_test() {
    let result = run(vec!["-h"]);
    assert_eq!(result.status, 0);
}

#[test]
fn version_test() {
    let result = run(vec!["--version"]);
    let version = env!("CARGO_PKG_VERSION");
    let expected = format!("to {}", version);

    assert_eq!(result.stdout, expected);
}
<|endoftext|>


<commit_before>extern crate assert;

extern crate tgff;

#[test]
fn parse_002_040() {
    let result = tgff::parse(&read_fixture("002_040.tgff")).unwrap();

    assert_eq!(result.attributes["HYPERPERIOD"], 8);
    assert_eq!(result.graphs.len(), 1);
    assert_eq!(result.tables.len(), 2);

    let graph = &result.graphs[0];
    assert_eq!(graph.name, "GRAPH");
    assert_eq!(graph.id, 0);
    assert_eq!(graph.attributes["PERIOD"], 8);
    assert_eq!(graph.tasks.len(), 40);
    assert_eq!(graph.arcs.len(), 52);
    assert_eq!(graph.deadlines.len(), 18);

    let prices = vec![10.5042, 14.8562];
    for i in (0..2) {
        let table = &result.tables[i];
        assert_eq!(table.name, "CORE");
        assert_eq!(table.id, i);
        assert_eq!(table.attributes["price"] as f32, prices[i]);
        assert_eq!(table.columns.len(), 4);
        assert_eq!(table.columns[0].name, "type");
        assert_eq!(table.columns[1].name, "version");
        assert_eq!(table.columns[2].name, "dynamic_power");
        assert_eq!(table.columns[3].name, "execution_time");
    }

    let dynamic_power = vec![
        14.41, 9.38, 14.19, 15.48, 12.15, 16.57, 16.98, 11.02, 17.6, 5.42,
        13.95, 7.08, 5.66, 18.08, 16.51, 5.86, 9.31, 17.25, 8.48, 7.29,
    ];
    assert::within(&result.tables[0].columns[2].data, &dynamic_power, 1e-14);

    let execution_time = vec![
        0.025, 0.019, 0.025, 0.026, 0.022, 0.027, 0.028, 0.021, 0.028, 0.015,
        0.024, 0.017, 0.015, 0.029, 0.027, 0.015, 0.019, 0.028, 0.018, 0.017,
    ];
    assert::within(&result.tables[0].columns[3].data, &execution_time, 1e-14);
}

#[test]
fn parse_032_640() {
    let result = tgff::parse(&read_fixture("032_640.tgff")).unwrap();

    assert_eq!(result.attributes["HYPERPERIOD"], 18);
    assert_eq!(result.graphs.len(), 1);
    assert_eq!(result.tables.len(), 32);

    let graph = &result.graphs[0];
    assert_eq!(graph.tasks.len(), 640);
    assert_eq!(graph.arcs.len(), 848);
    assert_eq!(graph.deadlines.len(), 259);

    for table in result.tables.iter() {
        assert_eq!(table.attributes.len(), 1);
        assert_eq!(table.columns.len(), 4);
        for column in table.columns.iter() {
            assert_eq!(column.data.len(), 320);
        }
    }
}

fn read_fixture(name: &str) -> String {
    use std::fs::File;
    use std::io::Read;
    use std::path::PathBuf;

    let path = PathBuf::from("tests").join("fixtures").join(name);

    let mut buffer = String::new();
    File::open(&path).unwrap().read_to_string(&mut buffer).unwrap();

    buffer
}
<commit_msg>Update the usage of assert<commit_after>extern crate assert;

extern crate tgff;

#[test]
fn parse_002_040() {
    let result = tgff::parse(&read_fixture("002_040.tgff")).unwrap();

    assert_eq!(result.attributes["HYPERPERIOD"], 8);
    assert_eq!(result.graphs.len(), 1);
    assert_eq!(result.tables.len(), 2);

    let graph = &result.graphs[0];
    assert_eq!(graph.name, "GRAPH");
    assert_eq!(graph.id, 0);
    assert_eq!(graph.attributes["PERIOD"], 8);
    assert_eq!(graph.tasks.len(), 40);
    assert_eq!(graph.arcs.len(), 52);
    assert_eq!(graph.deadlines.len(), 18);

    let prices = vec![10.5042, 14.8562];
    for i in (0..2) {
        let table = &result.tables[i];
        assert_eq!(table.name, "CORE");
        assert_eq!(table.id, i);
        assert_eq!(table.attributes["price"] as f32, prices[i]);
        assert_eq!(table.columns.len(), 4);
        assert_eq!(table.columns[0].name, "type");
        assert_eq!(table.columns[1].name, "version");
        assert_eq!(table.columns[2].name, "dynamic_power");
        assert_eq!(table.columns[3].name, "execution_time");
    }

    let dynamic_power = vec![
        14.41, 9.38, 14.19, 15.48, 12.15, 16.57, 16.98, 11.02, 17.6, 5.42,
        13.95, 7.08, 5.66, 18.08, 16.51, 5.86, 9.31, 17.25, 8.48, 7.29,
    ];
    assert::close(&result.tables[0].columns[2].data, &dynamic_power, 1e-14);

    let execution_time = vec![
        0.025, 0.019, 0.025, 0.026, 0.022, 0.027, 0.028, 0.021, 0.028, 0.015,
        0.024, 0.017, 0.015, 0.029, 0.027, 0.015, 0.019, 0.028, 0.018, 0.017,
    ];
    assert::close(&result.tables[0].columns[3].data, &execution_time, 1e-14);
}

#[test]
fn parse_032_640() {
    let result = tgff::parse(&read_fixture("032_640.tgff")).unwrap();

    assert_eq!(result.attributes["HYPERPERIOD"], 18);
    assert_eq!(result.graphs.len(), 1);
    assert_eq!(result.tables.len(), 32);

    let graph = &result.graphs[0];
    assert_eq!(graph.tasks.len(), 640);
    assert_eq!(graph.arcs.len(), 848);
    assert_eq!(graph.deadlines.len(), 259);

    for table in result.tables.iter() {
        assert_eq!(table.attributes.len(), 1);
        assert_eq!(table.columns.len(), 4);
        for column in table.columns.iter() {
            assert_eq!(column.data.len(), 320);
        }
    }
}

fn read_fixture(name: &str) -> String {
    use std::fs::File;
    use std::io::Read;
    use std::path::PathBuf;

    let path = PathBuf::from("tests").join("fixtures").join(name);

    let mut buffer = String::new();
    File::open(&path).unwrap().read_to_string(&mut buffer).unwrap();

    buffer
}
<|endoftext|>


<commit_before>extern crate glib;

use glib::*;

use std::sync::{Arc, Mutex};

#[derive(Default)]
struct Counters {
    errors: usize,
    criticals: usize,
    warnings: usize,
    messages: usize,
    infos: usize,
    debugs: usize,
}

fn assert_counts(
    count: &Arc<Mutex<Counters>>,
    errors: usize,
    criticals: usize,
    warnings: usize,
    messages: usize,
    infos: usize,
    debugs: usize,
) {
    let count = count.lock().expect("failed to lock 1");
    assert_eq!(count.errors, errors);
    assert_eq!(count.criticals, criticals);
    assert_eq!(count.warnings, warnings);
    assert_eq!(count.messages, messages);
    assert_eq!(count.infos, infos);
    assert_eq!(count.debugs, debugs);
}

#[test]
fn check_log_set_default_handler() {
    let count = Arc::new(Mutex::new(Counters::default()));
    log_set_default_handler(clone!(@strong count => move |_, level, _| {
        match level {
            LogLevel::Error => { (*count.lock().expect("failed to lock 2")).errors += 1; }
            LogLevel::Critical => { (*count.lock().expect("failed to lock 3")).criticals += 1; }
            LogLevel::Warning => { (*count.lock().expect("failed to lock 4")).warnings += 1; }
            LogLevel::Message => { (*count.lock().expect("failed to lock 5")).messages += 1; }
            LogLevel::Info => { (*count.lock().expect("failed to lock 6")).infos += 1; }
            LogLevel::Debug => { (*count.lock().expect("failed to lock 7")).debugs += 1; }
        }
    }));
    assert_counts(&count, 0, 0, 0, 0, 0, 0);
    g_error!("domain", "hello");
    assert_counts(&count, 1, 0, 0, 0, 0, 0);
    g_error!("domain", "hello");
    g_critical!("domain", "hello");
    g_warning!("domain", "hello");
    g_message!("domain", "hello");
    g_info!("domain", "hello");
    g_debug!("domain", "hello");
    g_info!("domain", "hello");
    assert_counts(&count, 2, 1, 1, 1, 2, 1);

    // We now unset our callback and check if it has really been unset.
    log_unset_default_handler();
    g_info!("domain", "hello");
    g_debug!("domain", "hello");
    assert_counts(&count, 2, 1, 1, 1, 2, 1);
}
<commit_msg>Working tests<commit_after>extern crate glib;

use glib::*;

use std::sync::{Arc, Mutex};

#[derive(Default)]
struct Counters {
    criticals: usize,
    warnings: usize,
    messages: usize,
    infos: usize,
    debugs: usize,
}

fn assert_counts(
    count: &Arc<Mutex<Counters>>,
    criticals: usize,
    warnings: usize,
    messages: usize,
    infos: usize,
    debugs: usize,
) {
    let count = count.lock().expect("failed to lock 1");
    assert_eq!(count.criticals, criticals);
    assert_eq!(count.warnings, warnings);
    assert_eq!(count.messages, messages);
    assert_eq!(count.infos, infos);
    assert_eq!(count.debugs, debugs);
}

#[test]
fn check_log_set_default_handler() {
    let count = Arc::new(Mutex::new(Counters::default()));
    log_set_default_handler(clone!(@strong count => move |_, level, _| {
        match level {
            LogLevel::Critical => { (*count.lock().expect("failed to lock 3")).criticals += 1; }
            LogLevel::Warning => { (*count.lock().expect("failed to lock 4")).warnings += 1; }
            LogLevel::Message => { (*count.lock().expect("failed to lock 5")).messages += 1; }
            LogLevel::Info => { (*count.lock().expect("failed to lock 6")).infos += 1; }
            LogLevel::Debug => { (*count.lock().expect("failed to lock 7")).debugs += 1; }
            _ => unreachable!(),
        }
    }));
    assert_counts(&count, 0, 0, 0, 0, 0);
    g_warning!("domain", "hello");
    assert_counts(&count, 0, 1, 0, 0, 0);
    g_warning!("domain", "hello");
    g_critical!("domain", "hello");
    g_warning!("domain", "hello");
    g_message!("domain", "hello");
    g_info!("domain", "hello");
    g_debug!("domain", "hello");
    g_info!("domain", "hello");
    assert_counts(&count, 1, 3, 1, 2, 1);

    // We now unset our callback and check if it has really been unset.
    log_unset_default_handler();
    g_info!("domain", "hello");
    g_debug!("domain", "hello");
    assert_counts(&count, 1, 3, 1, 2, 1);
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::hash::Hash;

/// An associative map data structure for representing scopes.
///
/// A `ForkTable` functions similarly to a standard associative map
/// data structure (such as a `HashMap`), but with the ability to
/// fork children off of each level of the map. If a key exists in any
/// of a child's parents, the child will 'pass through' that key. If a
/// new value is bound to a key in a child level, that child will overwrite
/// the previous entry with the new one, but the previous `key` -> `value`
/// mapping will remain in the level it is defined. This means that the parent
/// level will still provide the previous value for that key.
///
/// This is an implementation of the ForkTable data structure for
/// representing scopes. The ForkTable was initially described by
/// Max Clive. This implemention is based primarily by the Scala
/// reference implementation written by Hawk Weisman for the Decaf
/// compiler, which is available [here](https://github.com/hawkw/decaf/blob/master/src/main/scala/com/meteorcode/common/ForkTable.scala).
#[derive(Debug)]
pub struct ForkTable<'a, K:'a +  Eq + Hash,V: 'a>  {
    table: HashMap<K, V>,
    whiteouts: HashSet<K>,
    parent: Option<&'a mut ForkTable<'a, K,V>>
}

impl<'a, K,V> ForkTable<'a, K, V> where K: Eq + Hash {

    /// Returns a reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// assert_eq!(table.get(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get(&1isize), Some(&"One"));
    /// ```
    pub fn get<'b>(&'b self, key: &K) -> Option<&'b V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get(key)
                .or(match self.parent {
                        Some(ref parent)    => parent.get(key),
                        None                => None
                    })
        }
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&mut V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get_mut(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get_mut(&1isize), Some(&mut "One"));
    /// assert_eq!(table.get_mut(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get_mut(&1isize), Some(&mut "One"));
    /// ```
    /// TODO: consider only allowing `get_mut()` from the current
    ///       level, to remove the need to keep a mutable borrow
    ///       on the parent level. We could allow an overwrite here
    ///       instead.
   pub fn get_mut<'b>(&'b mut self, key: &K) -> Option<&'b mut V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get_mut(key)
                .or(match self.parent {
                        Some(ref mut parent)    => parent.get_mut(key),
                        None                    => None
                    })
        }
    }

    /// Removes a key from the map, returning the value at the key if
    /// the key was previously in the map.
    ///
    /// If the removed value exists in a lower level of the table,
    /// it will be whited out at this level. This means that the entry
    /// will be 'removed' at this level and this table will not provide
    /// access to it, but the mapping will still exist in the level where
    /// it was defined. Note that the key will not be returned if it is
    /// defined in a lower level of the table.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to remove
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// table.insert(1isize, "One");
    ///
    /// assert_eq!(table.remove(&1isize), Some("One"));
    /// assert_eq!(table.contains_key(&1isize), false);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// assert_eq!(level_2.remove(&1isize), None);
    /// assert_eq!(level_2.chain_contains_key(&1isize), false);
    /// ```
    ///
    pub fn remove(&mut self, key: &K) -> Option<V> where K: Clone {
            if self.table.contains_key(key) {
                self.table.remove(key)
            } else if self.chain_contains_key(key) {
                self.whiteouts.insert(key.clone()); // TODO: could just white out specific hashes?
                None
            } else {
                None
            }
    }

    /// Inserts a key-value pair from the map.
    ///
    /// If the key already had a value present in the map, that
    /// value is returned. Otherwise, `None` is returned.
    ///
    /// If the key is currently whited out (i.e. it was defined
    /// in a lower level of the map and was removed) then it will
    /// be un-whited out and added at this level.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to add
    ///  + `v`  - the value to associate with that key
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if a previous entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// Simply inserting an entry:
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// ```
    ///
    /// Overwriting the value associated with a key:
    ///
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// assert_eq!(table.insert(1isize, "two"), None);
    /// assert_eq!(table.get(&1isize), Some(&"two"));
    ///
    /// assert_eq!(table.insert(2isize, "Two"), Some("two"));
    /// assert_eq!(table.get(&2isize), Some(&"Two"));
    /// ```
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
        self.table.insert(k, v)
    }

    /// Returns true if this level contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in this level of the
    ///    table, `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.contains_key(&1isize), false);
    /// ```
    pub fn contains_key(&self, key: &K) -> bool  {
        self.table.contains_key(key)
    }

    /// Returns true if the key is defined in this level of the table, or
    /// in any of its' parents and is not whited out.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in the table,
    ///    `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.chain_contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.chain_contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.chain_contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.chain_contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// ```
    pub fn chain_contains_key(&self, key: &K) -> bool {
        self.table.contains_key(key) ||
        (self.whiteouts.contains(key) &&
            match self.parent {
                Some(ref p) => p.chain_contains_key(key),
                None        => false
            })
    }

    /// Forks this table, returning a new `ForkTable<K,V>`.
    ///
    /// This level of the table will be set as the child's
    /// parent. The child will be created with an empty backing
    /// `HashMap` and no keys whited out.
    ///
    /// Note that the new `ForkTable<K,V>` has a lifetime
    /// bound ensuring that it will live at least as long as the
    /// parent `ForkTable`.
    ///
    /// TODO: should whiteouts be carried over? look into this.
    pub fn fork(&'a mut self) -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: Some(self)
        }
    }

    /// Constructs a new `ForkTable<K,V>`
    pub fn new() -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: None
        }
    }
}<commit_msg>Fixed issues in contains_key and chain_contains_key<commit_after>use std::collections::{HashMap, HashSet};
use std::hash::Hash;

/// An associative map data structure for representing scopes.
///
/// A `ForkTable` functions similarly to a standard associative map
/// data structure (such as a `HashMap`), but with the ability to
/// fork children off of each level of the map. If a key exists in any
/// of a child's parents, the child will 'pass through' that key. If a
/// new value is bound to a key in a child level, that child will overwrite
/// the previous entry with the new one, but the previous `key` -> `value`
/// mapping will remain in the level it is defined. This means that the parent
/// level will still provide the previous value for that key.
///
/// This is an implementation of the ForkTable data structure for
/// representing scopes. The ForkTable was initially described by
/// Max Clive. This implemention is based primarily by the Scala
/// reference implementation written by Hawk Weisman for the Decaf
/// compiler, which is available [here](https://github.com/hawkw/decaf/blob/master/src/main/scala/com/meteorcode/common/ForkTable.scala).
#[derive(Debug)]
pub struct ForkTable<'a, K:'a +  Eq + Hash,V: 'a>  {
    table: HashMap<K, V>,
    whiteouts: HashSet<K>,
    parent: Option<&'a mut ForkTable<'a, K,V>>
}

impl<'a, K,V> ForkTable<'a, K, V> where K: Eq + Hash {

    /// Returns a reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// assert_eq!(table.get(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get(&1isize), Some(&"One"));
    /// ```
    #[stable]
    pub fn get<'b>(&'b self, key: &K) -> Option<&'b V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get(key)
                .or(match self.parent {
                        Some(ref parent)    => parent.get(key),
                        None                => None
                    })
        }
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&mut V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get_mut(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get_mut(&1isize), Some(&mut "One"));
    /// assert_eq!(table.get_mut(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get_mut(&1isize), Some(&mut "One"));
    /// ```
    /// TODO: consider only allowing `get_mut()` from the current
    ///       level, to remove the need to keep a mutable borrow
    ///       on the parent level. We could allow an overwrite here
    ///       instead.
   pub fn get_mut<'b>(&'b mut self, key: &K) -> Option<&'b mut V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get_mut(key)
                .or(match self.parent {
                        Some(ref mut parent)    => parent.get_mut(key),
                        None                    => None
                    })
        }
    }

    /// Removes a key from the map, returning the value at the key if
    /// the key was previously in the map.
    ///
    /// If the removed value exists in a lower level of the table,
    /// it will be whited out at this level. This means that the entry
    /// will be 'removed' at this level and this table will not provide
    /// access to it, but the mapping will still exist in the level where
    /// it was defined. Note that the key will not be returned if it is
    /// defined in a lower level of the table.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to remove
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// table.insert(1isize, "One");
    ///
    /// assert_eq!(table.remove(&1isize), Some("One"));
    /// assert_eq!(table.contains_key(&1isize), false);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// assert_eq!(level_2.remove(&1isize), None);
    /// assert_eq!(level_2.chain_contains_key(&1isize), false);
    /// ```
    ///
    pub fn remove(&mut self, key: &K) -> Option<V> where K: Clone {
            if self.table.contains_key(key) {
                self.table.remove(key)
            } else if self.chain_contains_key(key) {
                self.whiteouts.insert(key.clone()); // TODO: could just white out specific hashes?
                None
            } else {
                None
            }
    }

    /// Inserts a key-value pair from the map.
    ///
    /// If the key already had a value present in the map, that
    /// value is returned. Otherwise, `None` is returned.
    ///
    /// If the key is currently whited out (i.e. it was defined
    /// in a lower level of the map and was removed) then it will
    /// be un-whited out and added at this level.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to add
    ///  + `v`  - the value to associate with that key
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if a previous entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// Simply inserting an entry:
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// ```
    ///
    /// Overwriting the value associated with a key:
    ///
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// assert_eq!(table.insert(1isize, "two"), None);
    /// assert_eq!(table.get(&1isize), Some(&"two"));
    ///
    /// assert_eq!(table.insert(2isize, "Two"), Some("two"));
    /// assert_eq!(table.get(&2isize), Some(&"Two"));
    /// ```
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
        self.table.insert(k, v)
    }

    /// Returns true if this level contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in this level of the
    ///    table, `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.contains_key(&1isize), false);
    /// ```
    #[stable]
    pub fn contains_key(&self, key: &K) -> bool  {
        !self.whiteouts.contains(key)  &&
        self.table.contains_key(key)
    }

    /// Returns true if the key is defined in this level of the table, or
    /// in any of its' parents and is not whited out.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in the table,
    ///    `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.chain_contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.chain_contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.chain_contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.chain_contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// ```
    #[stable]
    pub fn chain_contains_key(&self, key: &K) -> bool {
        self.table.contains_key(key) ||
        (!self.whiteouts.contains(key) &&
            match self.parent {
                Some(ref p) => p.chain_contains_key(key),
                None        => false
            })
    }

    /// Forks this table, returning a new `ForkTable<K,V>`.
    ///
    /// This level of the table will be set as the child's
    /// parent. The child will be created with an empty backing
    /// `HashMap` and no keys whited out.
    ///
    /// Note that the new `ForkTable<K,V>` has a lifetime
    /// bound ensuring that it will live at least as long as the
    /// parent `ForkTable`.
    ///
    /// TODO: should whiteouts be carried over? look into this.
    pub fn fork(&'a mut self) -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: Some(self)
        }
    }

    /// Constructs a new `ForkTable<K,V>`
    pub fn new() -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: None
        }
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Defines how the color output of the fragment shader is written to the attachment.
//!
//! There are three kinds of color attachments for the purpose of blending:
//!
//! - Attachments with a floating-point, fixed point format.
//! - Attachments with a (non-normalized) integer format.
//! - Attachments with a normalized integer format.
//!
//! For floating-point and fixed-point formats, the blending operation is applied. For integer
//! formats, the logic operation is applied. For normalized integer formats, the logic operation
//! will take precedence if it is activated, otherwise the blending operation is applied.
//!

use vk;

#[derive(Debug, Clone, PartialEq)]
pub struct Blend {
    pub logic_op: Option<LogicOp>,

    pub attachments: AttachmentsBlend,

    /// The constant color to use for the `Constant*` blending operation.
    ///
    /// If you pass `None`, then this state will be considered as dynamic and the blend constants
    /// will need to be set when you build the command buffer.
    pub blend_constants: Option<[f32; 4]>,
}

impl Blend {
    /// Returns a `Blend` object that directly writes colors and alpha on the surface.
    #[inline]
    pub fn pass_through() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: false,
                color_op: BlendOp::Add,
                color_src: BlendFactor::Zero,
                color_dst: BlendFactor::One,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::Zero,
                alpha_dst: BlendFactor::One,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }

    /// Returns a `Blend` object that adds transparent objects over others.
    #[inline]
    pub fn alpha_blending() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: true,
                color_op: BlendOp::Add,
                color_src: BlendFactor::SrcAlpha,
                color_dst: BlendFactor::OneMinusSrcAlpha,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::SrcAlpha,
                alpha_dst: BlendFactor::OneMinusSrcAlpha,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttachmentsBlend {
    Collective(AttachmentBlend),
    Individual(Vec<AttachmentBlend>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AttachmentBlend {
    // TODO: could be automatically determined from the other params
    pub enabled: bool,

    pub color_op: BlendOp,
    pub color_src: BlendFactor,
    pub color_dst: BlendFactor,

    pub alpha_op: BlendOp,
    pub alpha_src: BlendFactor,
    pub alpha_dst: BlendFactor,

    pub mask_red: bool,
    pub mask_green: bool,
    pub mask_blue: bool,
    pub mask_alpha: bool,
}

#[doc(hidden)]
impl Into<vk::PipelineColorBlendAttachmentState> for AttachmentBlend {
    #[inline]
    fn into(self) -> vk::PipelineColorBlendAttachmentState {
        vk::PipelineColorBlendAttachmentState {
            blendEnable: if self.enabled { vk::TRUE } else { vk::FALSE },
            srcColorBlendFactor: self.color_src as u32,
            dstColorBlendFactor: self.color_dst as u32,
            colorBlendOp: self.color_op as u32,
            srcAlphaBlendFactor: self.alpha_src as u32,
            dstAlphaBlendFactor: self.alpha_dst as u32,
            alphaBlendOp: self.alpha_op as u32,
            colorWriteMask: {
                let mut mask = 0;
                if self.mask_red { mask |= vk::COLOR_COMPONENT_R_BIT; }
                if self.mask_green { mask |= vk::COLOR_COMPONENT_G_BIT; }
                if self.mask_blue { mask |= vk::COLOR_COMPONENT_B_BIT; }
                if self.mask_alpha { mask |= vk::COLOR_COMPONENT_A_BIT; }
                mask
            },
        }
    }
}

/// Which logical operation to apply to the output values.
///
/// The operation is applied individually for each channel (red, green, blue and alpha).
///
/// Only relevant for integer or unsigned attachments.
///
/// Also note that some implementations don't support logic operations.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum LogicOp {
    /// Returns `0`.
    Clear = vk::LOGIC_OP_CLEAR,
    /// Returns `src & dest`.
    And = vk::LOGIC_OP_AND,
    /// Returns `src & !dest`.
    AndReverse = vk::LOGIC_OP_AND_REVERSE,
    /// Returns `src`.
    Copy = vk::LOGIC_OP_COPY,
    /// Returns `!src & dest`.
    AndInverted = vk::LOGIC_OP_AND_INVERTED,
    /// Returns `dest`.
    Noop = vk::LOGIC_OP_NO_OP,
    /// Returns `src ^ dest`.
    Xor = vk::LOGIC_OP_XOR,
    /// Returns `src | dest`.
    Or = vk::LOGIC_OP_OR,
    /// Returns `!(src | dest)`.
    Nor = vk::LOGIC_OP_NOR,
    /// Returns `!(src ^ dest)`.
    Equivalent = vk::LOGIC_OP_EQUIVALENT,
    /// Returns `!dest`.
    Invert = vk::LOGIC_OP_INVERT,
    /// Returns `src | !dest.
    OrReverse = vk::LOGIC_OP_OR_REVERSE,
    /// Returns `!src`.
    CopyInverted = vk::LOGIC_OP_COPY_INVERTED,
    /// Returns `!src | dest`.
    OrInverted = vk::LOGIC_OP_OR_INVERTED,
    /// Returns `!(src & dest)`.
    Nand = vk::LOGIC_OP_NAND,
    /// Returns `!0` (all bits set to 1).
    Set = vk::LOGIC_OP_SET,
}

impl Default for LogicOp {
    #[inline]
    fn default() -> LogicOp {
        LogicOp::Noop
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendOp {
    Add = vk::BLEND_OP_ADD,
    Subtract = vk::BLEND_OP_SUBTRACT,
    ReverseSubtract = vk::BLEND_OP_REVERSE_SUBTRACT,
    Min = vk::BLEND_OP_MIN,
    Max = vk::BLEND_OP_MAX,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendFactor {
    Zero = vk::BLEND_FACTOR_ZERO,
    One = vk::BLEND_FACTOR_ONE,
    SrcColor = vk::BLEND_FACTOR_SRC_COLOR,
    OneMinusSrcColor = vk::BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
    DstColor = vk::BLEND_FACTOR_DST_COLOR,
    OneMinusDstColor = vk::BLEND_FACTOR_ONE_MINUS_DST_COLOR,
    SrcAlpha = vk::BLEND_FACTOR_SRC_ALPHA,
    OneMinusSrcAlpha = vk::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
    DstAlpha = vk::BLEND_FACTOR_DST_ALPHA,
    OneMinusDstAlpha = vk::BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
    ConstantColor = vk::BLEND_FACTOR_CONSTANT_COLOR,
    OneMinusConstantColor = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
    ConstantAlpha = vk::BLEND_FACTOR_CONSTANT_ALPHA,
    OneMinusConstantAlpha = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
    SrcAlphaSaturate = vk::BLEND_FACTOR_SRC_ALPHA_SATURATE,
    Src1Color = vk::BLEND_FACTOR_SRC1_COLOR,
    OneMinusSrc1Color = vk::BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
    Src1Alpha = vk::BLEND_FACTOR_SRC1_ALPHA,
    OneMinusSrc1Alpha = vk::BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
}
<commit_msg>Add some utilities and documentation for blending<commit_after>// Copyright (c) 2016 The vulkano 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Defines how the color output of the fragment shader is written to the attachment.
//!
//! # Blending in details
//!
//! There are three kinds of color attachments for the purpose of blending:
//!
//! - Attachments with a floating-point, fixed point format.
//! - Attachments with a (non-normalized) integer format.
//! - Attachments with a normalized integer format.
//!
//! For floating-point and fixed-point formats, the blending operation is applied. For integer
//! formats, the logic operation is applied. For normalized integer formats, the logic operation
//! will take precedence if it is activated, otherwise the blending operation is applied.
//!

use vk;

/// Describes how the color output of the fragment shader is written to the attachment. See the
/// documentation of the `blend` module for more info.
#[derive(Debug, Clone, PartialEq)]
pub struct Blend {
    pub logic_op: Option<LogicOp>,

    pub attachments: AttachmentsBlend,

    /// The constant color to use for the `Constant*` blending operation.
    ///
    /// If you pass `None`, then this state will be considered as dynamic and the blend constants
    /// will need to be set when you build the command buffer.
    pub blend_constants: Option<[f32; 4]>,
}

impl Blend {
    /// Returns a `Blend` object that directly writes colors and alpha on the surface.
    #[inline]
    pub fn pass_through() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend::pass_through()),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }

    /// Returns a `Blend` object that adds transparent objects over others.
    #[inline]
    pub fn alpha_blending() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend::alpha_blending()),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }
}

/// Describes how the blending system should behave.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttachmentsBlend {
    /// All the framebuffer attachments will use the same blending.
    Collective(AttachmentBlend),

    /// Each attachment will behave differently. Note that this requires enabling the
    /// `independent_blend` feature.
    Individual(Vec<AttachmentBlend>),
}

/// Describes how the blending system should behave for an individual attachment.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AttachmentBlend {
    // TODO: could be automatically determined from the other params
    /// If false, blending is ignored and the output is directly written to the attachment.
    pub enabled: bool,

    pub color_op: BlendOp,
    pub color_src: BlendFactor,
    pub color_dst: BlendFactor,

    pub alpha_op: BlendOp,
    pub alpha_src: BlendFactor,
    pub alpha_dst: BlendFactor,

    pub mask_red: bool,
    pub mask_green: bool,
    pub mask_blue: bool,
    pub mask_alpha: bool,
}

impl AttachmentBlend {
    /// Builds an `AttachmentBlend` where blending is disabled.
    #[inline]
    pub fn pass_through() -> AttachmentBlend {
        AttachmentBlend {
            enabled: false,
            color_op: BlendOp::Add,
            color_src: BlendFactor::Zero,
            color_dst: BlendFactor::One,
            alpha_op: BlendOp::Add,
            alpha_src: BlendFactor::Zero,
            alpha_dst: BlendFactor::One,
            mask_red: true,
            mask_green: true,
            mask_blue: true,
            mask_alpha: true,
        }
    }

    /// Builds an `AttachmentBlend` where the output of the fragment shader is ignored and the
    /// destination is untouched.
    #[inline]
    pub fn ignore_source() -> AttachmentBlend {
        AttachmentBlend {
            enabled: true,
            color_op: BlendOp::Add,
            color_src: BlendFactor::Zero,
            color_dst: BlendFactor::DstColor,
            alpha_op: BlendOp::Add,
            alpha_src: BlendFactor::Zero,
            alpha_dst: BlendFactor::DstColor,
            mask_red: true,
            mask_green: true,
            mask_blue: true,
            mask_alpha: true,
        }
    }

    /// Builds an `AttachmentBlend` where the output will be merged with the existing value
    /// based on the alpha of the source.
    #[inline]
    pub fn alpha_blending() -> AttachmentBlend {
        AttachmentBlend {
            enabled: true,
            color_op: BlendOp::Add,
            color_src: BlendFactor::SrcAlpha,
            color_dst: BlendFactor::OneMinusSrcAlpha,
            alpha_op: BlendOp::Add,
            alpha_src: BlendFactor::SrcAlpha,
            alpha_dst: BlendFactor::OneMinusSrcAlpha,
            mask_red: true,
            mask_green: true,
            mask_blue: true,
            mask_alpha: true,
        }
    }
}

#[doc(hidden)]
impl Into<vk::PipelineColorBlendAttachmentState> for AttachmentBlend {
    #[inline]
    fn into(self) -> vk::PipelineColorBlendAttachmentState {
        vk::PipelineColorBlendAttachmentState {
            blendEnable: if self.enabled { vk::TRUE } else { vk::FALSE },
            srcColorBlendFactor: self.color_src as u32,
            dstColorBlendFactor: self.color_dst as u32,
            colorBlendOp: self.color_op as u32,
            srcAlphaBlendFactor: self.alpha_src as u32,
            dstAlphaBlendFactor: self.alpha_dst as u32,
            alphaBlendOp: self.alpha_op as u32,
            colorWriteMask: {
                let mut mask = 0;
                if self.mask_red { mask |= vk::COLOR_COMPONENT_R_BIT; }
                if self.mask_green { mask |= vk::COLOR_COMPONENT_G_BIT; }
                if self.mask_blue { mask |= vk::COLOR_COMPONENT_B_BIT; }
                if self.mask_alpha { mask |= vk::COLOR_COMPONENT_A_BIT; }
                mask
            },
        }
    }
}

/// Which logical operation to apply to the output values.
///
/// The operation is applied individually for each channel (red, green, blue and alpha).
///
/// Only relevant for integer or unsigned attachments.
///
/// Also note that some implementations don't support logic operations.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum LogicOp {
    /// Returns `0`.
    Clear = vk::LOGIC_OP_CLEAR,
    /// Returns `src & dest`.
    And = vk::LOGIC_OP_AND,
    /// Returns `src & !dest`.
    AndReverse = vk::LOGIC_OP_AND_REVERSE,
    /// Returns `src`.
    Copy = vk::LOGIC_OP_COPY,
    /// Returns `!src & dest`.
    AndInverted = vk::LOGIC_OP_AND_INVERTED,
    /// Returns `dest`.
    Noop = vk::LOGIC_OP_NO_OP,
    /// Returns `src ^ dest`.
    Xor = vk::LOGIC_OP_XOR,
    /// Returns `src | dest`.
    Or = vk::LOGIC_OP_OR,
    /// Returns `!(src | dest)`.
    Nor = vk::LOGIC_OP_NOR,
    /// Returns `!(src ^ dest)`.
    Equivalent = vk::LOGIC_OP_EQUIVALENT,
    /// Returns `!dest`.
    Invert = vk::LOGIC_OP_INVERT,
    /// Returns `src | !dest.
    OrReverse = vk::LOGIC_OP_OR_REVERSE,
    /// Returns `!src`.
    CopyInverted = vk::LOGIC_OP_COPY_INVERTED,
    /// Returns `!src | dest`.
    OrInverted = vk::LOGIC_OP_OR_INVERTED,
    /// Returns `!(src & dest)`.
    Nand = vk::LOGIC_OP_NAND,
    /// Returns `!0` (all bits set to 1).
    Set = vk::LOGIC_OP_SET,
}

impl Default for LogicOp {
    #[inline]
    fn default() -> LogicOp {
        LogicOp::Noop
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendOp {
    Add = vk::BLEND_OP_ADD,
    Subtract = vk::BLEND_OP_SUBTRACT,
    ReverseSubtract = vk::BLEND_OP_REVERSE_SUBTRACT,
    Min = vk::BLEND_OP_MIN,
    Max = vk::BLEND_OP_MAX,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendFactor {
    Zero = vk::BLEND_FACTOR_ZERO,
    One = vk::BLEND_FACTOR_ONE,
    SrcColor = vk::BLEND_FACTOR_SRC_COLOR,
    OneMinusSrcColor = vk::BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
    DstColor = vk::BLEND_FACTOR_DST_COLOR,
    OneMinusDstColor = vk::BLEND_FACTOR_ONE_MINUS_DST_COLOR,
    SrcAlpha = vk::BLEND_FACTOR_SRC_ALPHA,
    OneMinusSrcAlpha = vk::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
    DstAlpha = vk::BLEND_FACTOR_DST_ALPHA,
    OneMinusDstAlpha = vk::BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
    ConstantColor = vk::BLEND_FACTOR_CONSTANT_COLOR,
    OneMinusConstantColor = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
    ConstantAlpha = vk::BLEND_FACTOR_CONSTANT_ALPHA,
    OneMinusConstantAlpha = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
    SrcAlphaSaturate = vk::BLEND_FACTOR_SRC_ALPHA_SATURATE,
    Src1Color = vk::BLEND_FACTOR_SRC1_COLOR,
    OneMinusSrc1Color = vk::BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
    Src1Alpha = vk::BLEND_FACTOR_SRC1_ALPHA,
    OneMinusSrc1Alpha = vk::BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "unstable", feature(core))]

extern crate itertools;

use std::fmt::Debug;
#[cfg(feature = "unstable")]
use std::iter::RandomAccessIterator;
use itertools::Itertools;
use itertools::EitherOrBoth::{Both, Left, Right};
use itertools::{
    Zip,
};
#[cfg(feature = "unstable")]
use itertools::ZipTrusted;

#[test]
fn zip_longest_fused()
{
    let a = [Some(1), None, Some(3), Some(4)];
    let b = [1, 2, 3];

    let unfused = a.iter().batching(|mut it| *it.next().unwrap())
        .zip_longest(b.iter().cloned());
    assert_iters_equal(unfused,
                       vec![Both(1, 1), Right(2), Right(3)]);
}

#[cfg(feature = "unstable")]
#[test]
fn test_zip_longest_size_hint() {
    let c = (1..10).cycle();
    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let v2 = &[10, 11, 12];

    assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None));

    assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10)));
}

#[test]
fn test_double_ended_zip_longest() {
    let xs = [1, 2, 3, 4, 5, 6];
    let ys = [1, 2, 3, 7];
    let a = xs.iter().map(|&x| x);
    let b = ys.iter().map(|&x| x);
    let mut it = a.zip_longest(b);
    assert_eq!(it.next(), Some(Both(1, 1)));
    assert_eq!(it.next(), Some(Both(2, 2)));
    assert_eq!(it.next_back(), Some(Left(6)));
    assert_eq!(it.next_back(), Some(Left(5)));
    assert_eq!(it.next_back(), Some(Both(4, 7)));
    assert_eq!(it.next(), Some(Both(3, 3)));
    assert_eq!(it.next(), None);
}

#[cfg(feature = "unstable")]
// This function copied from std::iter in rust-lang/rust
#[cfg(test)]
fn check_randacc_iter<A, T>(a: T, len: usize) where
    A: PartialEq,
    T: Clone + Iterator<Item=A> + RandomAccessIterator
{
    let mut b = a.clone();
    assert_eq!(len, b.indexable());
    let mut n = 0;
    for (i, elt) in a.enumerate() {
        assert!(Some(elt) == b.idx(i));
        n += 1;
    }
    assert_eq!(n, len);
    assert!(None == b.idx(n));
    // call recursively to check after picking off an element
    if len > 0 {
        b.next();
        check_randacc_iter(b, len-1);
    }
}

#[cfg(feature = "unstable")]
#[test]
fn test_random_access_zip_longest() {
    let xs = [1, 2, 3, 4, 5];
    let ys = [7, 9, 11];
    check_randacc_iter(xs.iter().zip_longest(ys.iter()), std::cmp::max(xs.len(), ys.len()));
}

#[test]
fn zip_tuple() {
    let xs = [1, 2, 3];
    let ys = b"ab";
    let mut it = Zip::new((xs.iter().cloned(), ));
    assert!(it.next() != None);
    let mut jt = Zip::new((xs.iter().cloned(), ys.iter().cloned()));
    assert_eq!(jt.next(), Some((1, b'a')));
    assert_eq!(jt.next(), Some((2, b'b')));
    assert_eq!(jt.next(), None);

    let mut jt = Zip::new((xs.iter().cloned(), xs.iter().cloned(), xs.iter().cloned()));
    assert_eq!(jt.next(), Some((1, 1, 1)));
}

fn assert_iters_equal<
    A: PartialEq + Debug,
    I: IntoIterator<Item=A>,
    J: IntoIterator<Item=A>>(it: I, jt: J)
{
    let mut it = it.into_iter();
    let mut jt = jt.into_iter();
    loop {
        let elti = it.next();
        let eltj = jt.next();
        assert_eq!(elti, eltj);
        if elti.is_none() { break; }
    }
}

#[cfg(feature = "unstable")]
#[test]
fn ziptrusted_1() {
    let mut xs = [0; 6];
    let mut ys = [0; 8];
    let mut zs = [0; 7];

    xs.iter_mut().set_from(0..);
    ys.iter_mut().set_from(0..);
    zs.iter_mut().set_from(0..);

    let it = ZipTrusted::new((xs.iter(), ys.iter()));
    assert_eq!(it.size_hint(), (6, Some(6)));
    assert_iters_equal(it, xs.iter().zip(ys.iter()));

    let it = ZipTrusted::new((xs.iter(), ys.iter(), zs.iter()));
    assert_eq!(it.size_hint(), (6, Some(6)));
    assert_iters_equal(it, xs.iter()
                             .zip(ys.iter())
                             .zip(zs.iter())
                             .map(|((a, b), c)| (a, b, c)));
}
<commit_msg>Remove duplicate Zip test<commit_after>#![cfg_attr(feature = "unstable", feature(core))]

extern crate itertools;

use std::fmt::Debug;
#[cfg(feature = "unstable")]
use std::iter::RandomAccessIterator;
use itertools::Itertools;
use itertools::EitherOrBoth::{Both, Left, Right};
#[cfg(feature = "unstable")]
use itertools::ZipTrusted;

#[test]
fn zip_longest_fused()
{
    let a = [Some(1), None, Some(3), Some(4)];
    let b = [1, 2, 3];

    let unfused = a.iter().batching(|mut it| *it.next().unwrap())
        .zip_longest(b.iter().cloned());
    assert_iters_equal(unfused,
                       vec![Both(1, 1), Right(2), Right(3)]);
}

#[cfg(feature = "unstable")]
#[test]
fn test_zip_longest_size_hint() {
    let c = (1..10).cycle();
    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let v2 = &[10, 11, 12];

    assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None));

    assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10)));
}

#[test]
fn test_double_ended_zip_longest() {
    let xs = [1, 2, 3, 4, 5, 6];
    let ys = [1, 2, 3, 7];
    let a = xs.iter().map(|&x| x);
    let b = ys.iter().map(|&x| x);
    let mut it = a.zip_longest(b);
    assert_eq!(it.next(), Some(Both(1, 1)));
    assert_eq!(it.next(), Some(Both(2, 2)));
    assert_eq!(it.next_back(), Some(Left(6)));
    assert_eq!(it.next_back(), Some(Left(5)));
    assert_eq!(it.next_back(), Some(Both(4, 7)));
    assert_eq!(it.next(), Some(Both(3, 3)));
    assert_eq!(it.next(), None);
}

#[cfg(feature = "unstable")]
// This function copied from std::iter in rust-lang/rust
#[cfg(test)]
fn check_randacc_iter<A, T>(a: T, len: usize) where
    A: PartialEq,
    T: Clone + Iterator<Item=A> + RandomAccessIterator
{
    let mut b = a.clone();
    assert_eq!(len, b.indexable());
    let mut n = 0;
    for (i, elt) in a.enumerate() {
        assert!(Some(elt) == b.idx(i));
        n += 1;
    }
    assert_eq!(n, len);
    assert!(None == b.idx(n));
    // call recursively to check after picking off an element
    if len > 0 {
        b.next();
        check_randacc_iter(b, len-1);
    }
}

#[cfg(feature = "unstable")]
#[test]
fn test_random_access_zip_longest() {
    let xs = [1, 2, 3, 4, 5];
    let ys = [7, 9, 11];
    check_randacc_iter(xs.iter().zip_longest(ys.iter()), std::cmp::max(xs.len(), ys.len()));
}

fn assert_iters_equal<
    A: PartialEq + Debug,
    I: IntoIterator<Item=A>,
    J: IntoIterator<Item=A>>(it: I, jt: J)
{
    let mut it = it.into_iter();
    let mut jt = jt.into_iter();
    loop {
        let elti = it.next();
        let eltj = jt.next();
        assert_eq!(elti, eltj);
        if elti.is_none() { break; }
    }
}

#[cfg(feature = "unstable")]
#[test]
fn ziptrusted_1() {
    let mut xs = [0; 6];
    let mut ys = [0; 8];
    let mut zs = [0; 7];

    xs.iter_mut().set_from(0..);
    ys.iter_mut().set_from(0..);
    zs.iter_mut().set_from(0..);

    let it = ZipTrusted::new((xs.iter(), ys.iter()));
    assert_eq!(it.size_hint(), (6, Some(6)));
    assert_iters_equal(it, xs.iter().zip(ys.iter()));

    let it = ZipTrusted::new((xs.iter(), ys.iter(), zs.iter()));
    assert_eq!(it.size_hint(), (6, Some(6)));
    assert_iters_equal(it, xs.iter()
                             .zip(ys.iter())
                             .zip(zs.iter())
                             .map(|((a, b), c)| (a, b, c)));
}
<|endoftext|>


<commit_before>use std::env;
use std::fmt;
use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic;

use csv;

use Csv;

static XSV_INTEGRATION_TEST_DIR: &'static str = "xit";

static NEXT_ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

pub struct Workdir {
    root: PathBuf,
    dir: PathBuf,
    flexible: bool,
}

impl Workdir {
    pub fn new(name: &str) -> Workdir {
        let id = NEXT_ID.fetch_add(1, atomic::Ordering::SeqCst);
        let root = env::current_exe().unwrap()
                       .parent()
                       .expect("executable's directory")
                       .to_path_buf();
        let dir = root.join(XSV_INTEGRATION_TEST_DIR)
                      .join(name)
                      .join(&format!("test-{}", id));
        if let Err(err) = create_dir_all(&dir) {
            panic!("Could not create '{:?}': {}", dir, err);
        }
        Workdir { root: root, dir: dir, flexible: false }
    }

    pub fn flexible(mut self, yes: bool) -> Workdir {
        self.flexible = yes;
        self
    }

    pub fn create<T: Csv>(&self, name: &str, rows: T) {
        let mut wtr = csv::Writer::from_file(&self.path(name)).unwrap();
        for row in rows.to_vecs().into_iter() {
            wtr.write(row.iter()).unwrap();
        }
        wtr.flush().unwrap();
    }

    pub fn create_indexed<T: Csv>(&self, name: &str, rows: T) {
        self.create(name, rows);

        let mut cmd = self.command("index");
        cmd.arg(name);
        self.run(&mut cmd);
    }

    pub fn read_stdout<T: Csv>(&self, cmd: &mut process::Command) -> T {
        let mut rdr = csv::Reader::from_string(self.stdout::<String>(cmd))
                                  .has_headers(false);
        Csv::from_vecs(rdr.records().collect::<Result<_, _>>().unwrap())
    }

    pub fn command(&self, sub_command: &str) -> process::Command {
        let mut cmd = process::Command::new(&self.xsv_bin());
        cmd.current_dir(&self.dir).arg(sub_command);
        cmd
    }

    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        debug!("[{}]: {:?}", self.dir.display(), cmd);
        let o = cmd.output().unwrap();
        if !o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command failed but expected success!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr))
        }
        o
    }

    pub fn run(&self, cmd: &mut process::Command) {
        self.output(cmd);
    }

    pub fn stdout<T: FromStr>(&self, cmd: &mut process::Command) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        stdout.trim().parse().ok().expect(
            &format!("Could not convert from string: '{}'", stdout))
    }

    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }

    pub fn from_str<T: FromStr>(&self, name: &Path) -> T {
        let mut o = String::new();
        fs::File::open(name).unwrap().read_to_string(&mut o).unwrap();
        o.parse().ok().expect("fromstr")
    }

    pub fn path(&self, name: &str) -> PathBuf {
        self.dir.join(name)
    }

    pub fn xsv_bin(&self) -> PathBuf {
        self.root.join("xsv")
    }
}

impl fmt::Debug for Workdir {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "path={}", self.dir.display())
    }
}

fn create_dir_all<P: AsRef<Path>>(p: P) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = fs::create_dir_all(&p) {
            last_err = Some(err);
            ::std::thread::sleep_ms(500);
        } else {
            return Ok(())
        }
    }
    Err(last_err.unwrap())
}
<commit_msg>Add comment explaining crazy Travis hack.<commit_after>use std::env;
use std::fmt;
use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic;

use csv;

use Csv;

static XSV_INTEGRATION_TEST_DIR: &'static str = "xit";

static NEXT_ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

pub struct Workdir {
    root: PathBuf,
    dir: PathBuf,
    flexible: bool,
}

impl Workdir {
    pub fn new(name: &str) -> Workdir {
        let id = NEXT_ID.fetch_add(1, atomic::Ordering::SeqCst);
        let root = env::current_exe().unwrap()
                       .parent()
                       .expect("executable's directory")
                       .to_path_buf();
        let dir = root.join(XSV_INTEGRATION_TEST_DIR)
                      .join(name)
                      .join(&format!("test-{}", id));
        if let Err(err) = create_dir_all(&dir) {
            panic!("Could not create '{:?}': {}", dir, err);
        }
        Workdir { root: root, dir: dir, flexible: false }
    }

    pub fn flexible(mut self, yes: bool) -> Workdir {
        self.flexible = yes;
        self
    }

    pub fn create<T: Csv>(&self, name: &str, rows: T) {
        let mut wtr = csv::Writer::from_file(&self.path(name)).unwrap();
        for row in rows.to_vecs().into_iter() {
            wtr.write(row.iter()).unwrap();
        }
        wtr.flush().unwrap();
    }

    pub fn create_indexed<T: Csv>(&self, name: &str, rows: T) {
        self.create(name, rows);

        let mut cmd = self.command("index");
        cmd.arg(name);
        self.run(&mut cmd);
    }

    pub fn read_stdout<T: Csv>(&self, cmd: &mut process::Command) -> T {
        let mut rdr = csv::Reader::from_string(self.stdout::<String>(cmd))
                                  .has_headers(false);
        Csv::from_vecs(rdr.records().collect::<Result<_, _>>().unwrap())
    }

    pub fn command(&self, sub_command: &str) -> process::Command {
        let mut cmd = process::Command::new(&self.xsv_bin());
        cmd.current_dir(&self.dir).arg(sub_command);
        cmd
    }

    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        debug!("[{}]: {:?}", self.dir.display(), cmd);
        let o = cmd.output().unwrap();
        if !o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command failed but expected success!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr))
        }
        o
    }

    pub fn run(&self, cmd: &mut process::Command) {
        self.output(cmd);
    }

    pub fn stdout<T: FromStr>(&self, cmd: &mut process::Command) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        stdout.trim().parse().ok().expect(
            &format!("Could not convert from string: '{}'", stdout))
    }

    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }

    pub fn from_str<T: FromStr>(&self, name: &Path) -> T {
        let mut o = String::new();
        fs::File::open(name).unwrap().read_to_string(&mut o).unwrap();
        o.parse().ok().expect("fromstr")
    }

    pub fn path(&self, name: &str) -> PathBuf {
        self.dir.join(name)
    }

    pub fn xsv_bin(&self) -> PathBuf {
        self.root.join("xsv")
    }
}

impl fmt::Debug for Workdir {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "path={}", self.dir.display())
    }
}

// For whatever reason, `fs::create_dir_all` fails intermittently on Travis
// with a weird "file exists" error. Despite my best efforts to get to the
// bottom of it, I've decided a try-wait-and-retry hack is good enough.
fn create_dir_all<P: AsRef<Path>>(p: P) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = fs::create_dir_all(&p) {
            last_err = Some(err);
            ::std::thread::sleep_ms(500);
        } else {
            return Ok(())
        }
    }
    Err(last_err.unwrap())
}
<|endoftext|>


<commit_before>extern crate rocksdb;

use rocksdb::{Options, DB};

#[test]
fn test_pinnable_slice() {
    let path = "_rust_rocksdb_pinnable_slice_test";

    let mut opts = Options::default();
    opts.create_if_missing(true);
    let db = DB::open(&opts, path).unwrap();

    db.put(b"k1", b"value12345").unwrap();

    let result = db.get_pinned(b"k1");
    assert!(result.is_ok());

    let value = result.unwrap();
    assert!(value.is_some());

    let pinnable_slice = value.unwrap();

    assert_eq!(b"12345", &pinnable_slice[5..10]);
}
<commit_msg>Use DBPath in PinnableSlice test<commit_after>extern crate rocksdb;
mod util;

use rocksdb::{Options, DB};
use util::DBPath;

#[test]
fn test_pinnable_slice() {
    let path = DBPath::new("_rust_rocksdb_pinnable_slice_test");

    let mut opts = Options::default();
    opts.create_if_missing(true);
    let db = DB::open(&opts, &path).unwrap();

    db.put(b"k1", b"value12345").unwrap();

    let result = db.get_pinned(b"k1");
    assert!(result.is_ok());

    let value = result.unwrap();
    assert!(value.is_some());

    let pinnable_slice = value.unwrap();

    assert_eq!(b"12345", &pinnable_slice[5..10]);
}
<|endoftext|>


<commit_before>#[derive(Clone, Debug)]
pub struct AnyValue {
    inner: std::sync::Arc<dyn std::any::Any + Send + Sync + 'static>,
}

impl AnyValue {
    pub(crate) fn new(inner: impl std::any::Any + Send + Sync + 'static) -> Self {
        let inner = std::sync::Arc::new(inner);
        Self { inner }
    }

    pub(crate) fn downcast_ref<T: std::any::Any>(&self) -> Option<&T> {
        self.inner.downcast_ref::<T>()
    }
}
<commit_msg>fix(parser): Improve AnyValue debug output<commit_after>#[derive(Clone)]
pub struct AnyValue {
    inner: std::sync::Arc<dyn std::any::Any + Send + Sync + 'static>,
    // While we can extract `TypeId` from `inner`, the debug repr is of a number, so let's track
    // the type_name in debug builds.
    id: AnyValueId,
}

impl AnyValue {
    pub(crate) fn new<V: std::any::Any + Send + Sync + 'static>(inner: V) -> Self {
        let id = AnyValueId::of::<V>();
        let inner = std::sync::Arc::new(inner);
        Self { inner, id }
    }

    pub(crate) fn downcast_ref<T: std::any::Any>(&self) -> Option<&T> {
        self.inner.downcast_ref::<T>()
    }
}

impl std::fmt::Debug for AnyValue {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        f.debug_struct("AnyValue").field("inner", &self.id).finish()
    }
}

#[derive(Copy, Clone)]
pub(crate) struct AnyValueId {
    type_id: std::any::TypeId,
    #[cfg(debug_assertions)]
    type_name: &'static str,
}

impl AnyValueId {
    pub(crate) fn of<A: ?Sized + 'static>() -> Self {
        Self {
            type_id: std::any::TypeId::of::<A>(),
            #[cfg(debug_assertions)]
            type_name: std::any::type_name::<A>(),
        }
    }
}

impl PartialEq for AnyValueId {
    fn eq(&self, other: &Self) -> bool {
        self.type_id == other.type_id
    }
}

impl Eq for AnyValueId {}

impl PartialOrd for AnyValueId {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.type_id.partial_cmp(&other.type_id)
    }
}

impl Ord for AnyValueId {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.type_id.cmp(&other.type_id)
    }
}

impl std::hash::Hash for AnyValueId {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.type_id.hash(state);
    }
}

impl std::fmt::Debug for AnyValueId {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        #[cfg(not(debug_assertions))]
        {
            self.type_id.fmt(f)
        }
        #[cfg(debug_assertions)]
        {
            f.debug_struct(self.type_name).finish()
        }
    }
}

impl<'a, A: ?Sized + 'static> From<&'a A> for AnyValueId {
    fn from(_: &'a A) -> Self {
        Self::of::<A>()
    }
}

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

    #[test]
    #[cfg(debug_assertions)]
    fn debug_impl() {
        assert_eq!(format!("{:?}", AnyValue::new(5)), "AnyValue { inner: i32 }");
    }
}
<|endoftext|>


<commit_before>//! A control flow graph represented as mappings of extended basic blocks to their predecessors
//! and successors.
//!
//! Successors are represented as extended basic blocks while predecessors are represented by basic
//! blocks. Basic blocks are denoted by tuples of EBB and branch/jump instructions. Each
//! predecessor tuple corresponds to the end of a basic block.
//!
//! ```c
//!     Ebb0:
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         brz vx, Ebb1 ; end of basic block
//!
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         jmp Ebb2     ; end of basic block
//! ```
//!
//! Here `Ebb1` and `Ebb2` would each have a single predecessor denoted as `(Ebb0, brz)`
//! and `(Ebb0, jmp Ebb2)` respectively.

use ir::{Function, Inst, Ebb};
use ir::instructions::BranchInfo;
use entity_map::{EntityMap, Keys};
use std::collections::HashSet;

/// A basic block denoted by its enclosing Ebb and last instruction.
pub type BasicBlock = (Ebb, Inst);

/// A container for the successors and predecessors of some Ebb.
#[derive(Debug, Clone, Default)]
pub struct CFGNode {
    /// EBBs that are the targets of branches and jumps in this EBB.
    pub successors: Vec<Ebb>,
    /// Basic blocks that can branch or jump to this EBB.
    pub predecessors: Vec<BasicBlock>,
}

/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
/// and successors where predecessors are basic blocks and successors are
/// extended basic blocks.
#[derive(Debug)]
pub struct ControlFlowGraph {
    entry_block: Option<Ebb>,
    data: EntityMap<Ebb, CFGNode>,
}

impl ControlFlowGraph {
    /// Allocate a new blank control flow graph.
    pub fn new() -> ControlFlowGraph {
        ControlFlowGraph {
            entry_block: None,
            data: EntityMap::new(),
        }
    }

    /// Allocate and compute the control flow graph for `func`.
    pub fn with_function(func: &Function) -> ControlFlowGraph {
        let mut cfg = ControlFlowGraph::new();
        cfg.compute(func);
        cfg
    }

    /// Compute the control flow graph of `func`.
    ///
    /// This will clear and overwrite any information already stored in this data structure.
    pub fn compute(&mut self, func: &Function) {
        self.entry_block = func.layout.entry_block();
        self.data.clear();
        self.data.resize(func.dfg.num_ebbs());

        for ebb in &func.layout {
            for inst in func.layout.ebb_insts(ebb) {
                match func.dfg[inst].analyze_branch(&func.dfg.value_lists) {
                    BranchInfo::SingleDest(dest, _) => {
                        self.add_edge((ebb, inst), dest);
                    }
                    BranchInfo::Table(jt) => {
                        for (_, dest) in func.jump_tables[jt].entries() {
                            self.add_edge((ebb, inst), dest);
                        }
                    }
                    BranchInfo::NotABranch => {}
                }
            }
        }
    }

    fn add_edge(&mut self, from: BasicBlock, to: Ebb) {
        self.data[from.0].successors.push(to);
        self.data[to].predecessors.push(from);
    }

    /// Get the CFG predecessor basic blocks to `ebb`.
    pub fn get_predecessors(&self, ebb: Ebb) -> &[BasicBlock] {
        &self.data[ebb].predecessors
    }

    /// Get the CFG successors to `ebb`.
    pub fn get_successors(&self, ebb: Ebb) -> &[Ebb] {
        &self.data[ebb].successors
    }

    /// Return [reachable] ebbs in post-order.
    pub fn postorder_ebbs(&self) -> Vec<Ebb> {
        let entry_block = match self.entry_block {
            None => {
                return Vec::new();
            }
            Some(eb) => eb,
        };

        let mut grey = HashSet::new();
        let mut black = HashSet::new();
        let mut stack = vec![entry_block.clone()];
        let mut postorder = Vec::new();

        while !stack.is_empty() {
            let node = stack.pop().unwrap();
            if !grey.contains(&node) {
                // This is a white node. Mark it as gray.
                grey.insert(node);
                stack.push(node);
                // Get any children we've never seen before.
                for child in self.get_successors(node) {
                    if !grey.contains(child) {
                        stack.push(child.clone());
                    }
                }
            } else if !black.contains(&node) {
                postorder.push(node.clone());
                black.insert(node.clone());
            }
        }
        postorder
    }

    /// An iterator across all of the ebbs stored in the CFG.
    pub fn ebbs(&self) -> Keys<Ebb> {
        self.data.keys()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ir::{Function, InstBuilder, Cursor, types};

    #[test]
    fn empty() {
        let func = Function::new();
        let cfg = ControlFlowGraph::with_function(&func);
        assert_eq!(None, cfg.ebbs().next());
    }

    #[test]
    fn no_predecessors() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let cfg = ControlFlowGraph::with_function(&func);
        let nodes = cfg.ebbs().collect::<Vec<_>>();
        assert_eq!(nodes.len(), 3);

        let mut fun_ebbs = func.layout.ebbs();
        for ebb in nodes {
            assert_eq!(ebb, fun_ebbs.next().unwrap());
            assert_eq!(cfg.get_predecessors(ebb).len(), 0);
            assert_eq!(cfg.get_successors(ebb).len(), 0);
        }
    }

    #[test]
    fn branches_and_jumps() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let cond = func.dfg.append_ebb_arg(ebb0, types::I32);
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();

        let br_ebb0_ebb2;
        let br_ebb1_ebb1;
        let jmp_ebb0_ebb1;
        let jmp_ebb1_ebb2;

        {
            let dfg = &mut func.dfg;
            let cur = &mut Cursor::new(&mut func.layout);

            cur.insert_ebb(ebb0);
            br_ebb0_ebb2 = dfg.ins(cur).brnz(cond, ebb2, &[]);
            jmp_ebb0_ebb1 = dfg.ins(cur).jump(ebb1, &[]);

            cur.insert_ebb(ebb1);
            br_ebb1_ebb1 = dfg.ins(cur).brnz(cond, ebb1, &[]);
            jmp_ebb1_ebb2 = dfg.ins(cur).jump(ebb2, &[]);

            cur.insert_ebb(ebb2);
        }

        let cfg = ControlFlowGraph::with_function(&func);

        let ebb0_predecessors = cfg.get_predecessors(ebb0);
        let ebb1_predecessors = cfg.get_predecessors(ebb1);
        let ebb2_predecessors = cfg.get_predecessors(ebb2);

        let ebb0_successors = cfg.get_successors(ebb0);
        let ebb1_successors = cfg.get_successors(ebb1);
        let ebb2_successors = cfg.get_successors(ebb2);

        assert_eq!(ebb0_predecessors.len(), 0);
        assert_eq!(ebb1_predecessors.len(), 2);
        assert_eq!(ebb2_predecessors.len(), 2);

        assert_eq!(ebb1_predecessors.contains(&(ebb0, jmp_ebb0_ebb1)), true);
        assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);

        assert_eq!(ebb0_successors.len(), 2);
        assert_eq!(ebb1_successors.len(), 2);
        assert_eq!(ebb2_successors.len(), 0);

        assert_eq!(ebb0_successors.contains(&ebb1), true);
        assert_eq!(ebb0_successors.contains(&ebb2), true);
        assert_eq!(ebb1_successors.contains(&ebb1), true);
        assert_eq!(ebb1_successors.contains(&ebb2), true);
    }
}
<commit_msg>Added ControlFlowGraph::recompute_ebb for incremental CFG updates.<commit_after>//! A control flow graph represented as mappings of extended basic blocks to their predecessors
//! and successors.
//!
//! Successors are represented as extended basic blocks while predecessors are represented by basic
//! blocks. Basic blocks are denoted by tuples of EBB and branch/jump instructions. Each
//! predecessor tuple corresponds to the end of a basic block.
//!
//! ```c
//!     Ebb0:
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         brz vx, Ebb1 ; end of basic block
//!
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         jmp Ebb2     ; end of basic block
//! ```
//!
//! Here `Ebb1` and `Ebb2` would each have a single predecessor denoted as `(Ebb0, brz)`
//! and `(Ebb0, jmp Ebb2)` respectively.

use ir::{Function, Inst, Ebb};
use ir::instructions::BranchInfo;
use entity_map::{EntityMap, Keys};
use std::collections::HashSet;
use std::mem;

/// A basic block denoted by its enclosing Ebb and last instruction.
pub type BasicBlock = (Ebb, Inst);

/// A container for the successors and predecessors of some Ebb.
#[derive(Debug, Clone, Default)]
pub struct CFGNode {
    /// EBBs that are the targets of branches and jumps in this EBB.
    pub successors: Vec<Ebb>,
    /// Basic blocks that can branch or jump to this EBB.
    pub predecessors: Vec<BasicBlock>,
}

/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
/// and successors where predecessors are basic blocks and successors are
/// extended basic blocks.
#[derive(Debug)]
pub struct ControlFlowGraph {
    entry_block: Option<Ebb>,
    data: EntityMap<Ebb, CFGNode>,
}

impl ControlFlowGraph {
    /// Allocate a new blank control flow graph.
    pub fn new() -> ControlFlowGraph {
        ControlFlowGraph {
            entry_block: None,
            data: EntityMap::new(),
        }
    }

    /// Allocate and compute the control flow graph for `func`.
    pub fn with_function(func: &Function) -> ControlFlowGraph {
        let mut cfg = ControlFlowGraph::new();
        cfg.compute(func);
        cfg
    }

    /// Compute the control flow graph of `func`.
    ///
    /// This will clear and overwrite any information already stored in this data structure.
    pub fn compute(&mut self, func: &Function) {
        self.entry_block = func.layout.entry_block();
        self.data.clear();
        self.data.resize(func.dfg.num_ebbs());

        for ebb in &func.layout {
            self.compute_ebb(func, ebb);
        }
    }

    fn compute_ebb(&mut self, func: &Function, ebb: Ebb) {
        for inst in func.layout.ebb_insts(ebb) {
            match func.dfg[inst].analyze_branch(&func.dfg.value_lists) {
                BranchInfo::SingleDest(dest, _) => {
                    self.add_edge((ebb, inst), dest);
                }
                BranchInfo::Table(jt) => {
                    for (_, dest) in func.jump_tables[jt].entries() {
                        self.add_edge((ebb, inst), dest);
                    }
                }
                BranchInfo::NotABranch => {}
            }
        }
    }

    fn invalidate_ebb_successors(&mut self, ebb: Ebb) {
        // Temporarily take ownership because we need mutable access to self.data inside the loop.
        // Unfortunately borrowck cannot see that our mut accesses to predecessors don't alias
        // our iteration over successors.
        let mut successors = mem::replace(&mut self.data[ebb].successors, Vec::new());
        for suc in successors.iter().cloned() {
            self.data[suc].predecessors.retain(|&(e, _)| e != ebb);
        }
        successors.clear();
        self.data[ebb].successors = successors;
    }

    /// Recompute the control flow graph of `ebb`.
    ///
    /// This is for use after modifying instructions within a specific EBB. It recomputes all edges
    /// from `ebb` while leaving edges to `ebb` intact. Its functionality a subset of that of the
    /// more expensive `compute`, and should be used when we know we don't need to recompute the CFG
    /// from scratch, but rather that our changes have been restricted to specific EBBs.
    pub fn recompute_ebb(&mut self, func: &Function, ebb: Ebb) {
        self.invalidate_ebb_successors(ebb);
        self.compute_ebb(func, ebb);
    }

    fn add_edge(&mut self, from: BasicBlock, to: Ebb) {
        self.data[from.0].successors.push(to);
        self.data[to].predecessors.push(from);
    }

    /// Get the CFG predecessor basic blocks to `ebb`.
    pub fn get_predecessors(&self, ebb: Ebb) -> &[BasicBlock] {
        &self.data[ebb].predecessors
    }

    /// Get the CFG successors to `ebb`.
    pub fn get_successors(&self, ebb: Ebb) -> &[Ebb] {
        &self.data[ebb].successors
    }

    /// Return [reachable] ebbs in post-order.
    pub fn postorder_ebbs(&self) -> Vec<Ebb> {
        let entry_block = match self.entry_block {
            None => {
                return Vec::new();
            }
            Some(eb) => eb,
        };

        let mut grey = HashSet::new();
        let mut black = HashSet::new();
        let mut stack = vec![entry_block.clone()];
        let mut postorder = Vec::new();

        while !stack.is_empty() {
            let node = stack.pop().unwrap();
            if !grey.contains(&node) {
                // This is a white node. Mark it as gray.
                grey.insert(node);
                stack.push(node);
                // Get any children we've never seen before.
                for child in self.get_successors(node) {
                    if !grey.contains(child) {
                        stack.push(child.clone());
                    }
                }
            } else if !black.contains(&node) {
                postorder.push(node.clone());
                black.insert(node.clone());
            }
        }
        postorder
    }

    /// An iterator across all of the ebbs stored in the CFG.
    pub fn ebbs(&self) -> Keys<Ebb> {
        self.data.keys()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ir::{Function, InstBuilder, Cursor, types};

    #[test]
    fn empty() {
        let func = Function::new();
        let cfg = ControlFlowGraph::with_function(&func);
        assert_eq!(None, cfg.ebbs().next());
    }

    #[test]
    fn no_predecessors() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let cfg = ControlFlowGraph::with_function(&func);
        let nodes = cfg.ebbs().collect::<Vec<_>>();
        assert_eq!(nodes.len(), 3);

        let mut fun_ebbs = func.layout.ebbs();
        for ebb in nodes {
            assert_eq!(ebb, fun_ebbs.next().unwrap());
            assert_eq!(cfg.get_predecessors(ebb).len(), 0);
            assert_eq!(cfg.get_successors(ebb).len(), 0);
        }
    }

    #[test]
    fn branches_and_jumps() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let cond = func.dfg.append_ebb_arg(ebb0, types::I32);
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();

        let br_ebb0_ebb2;
        let br_ebb1_ebb1;
        let jmp_ebb0_ebb1;
        let jmp_ebb1_ebb2;

        {
            let dfg = &mut func.dfg;
            let cur = &mut Cursor::new(&mut func.layout);

            cur.insert_ebb(ebb0);
            br_ebb0_ebb2 = dfg.ins(cur).brnz(cond, ebb2, &[]);
            jmp_ebb0_ebb1 = dfg.ins(cur).jump(ebb1, &[]);

            cur.insert_ebb(ebb1);
            br_ebb1_ebb1 = dfg.ins(cur).brnz(cond, ebb1, &[]);
            jmp_ebb1_ebb2 = dfg.ins(cur).jump(ebb2, &[]);

            cur.insert_ebb(ebb2);
        }

        let mut cfg = ControlFlowGraph::with_function(&func);

        {
            let ebb0_predecessors = cfg.get_predecessors(ebb0);
            let ebb1_predecessors = cfg.get_predecessors(ebb1);
            let ebb2_predecessors = cfg.get_predecessors(ebb2);

            let ebb0_successors = cfg.get_successors(ebb0);
            let ebb1_successors = cfg.get_successors(ebb1);
            let ebb2_successors = cfg.get_successors(ebb2);

            assert_eq!(ebb0_predecessors.len(), 0);
            assert_eq!(ebb1_predecessors.len(), 2);
            assert_eq!(ebb2_predecessors.len(), 2);

            assert_eq!(ebb1_predecessors.contains(&(ebb0, jmp_ebb0_ebb1)), true);
            assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
            assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true);
            assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);

            assert_eq!(ebb0_successors.len(), 2);
            assert_eq!(ebb1_successors.len(), 2);
            assert_eq!(ebb2_successors.len(), 0);

            assert_eq!(ebb0_successors.contains(&ebb1), true);
            assert_eq!(ebb0_successors.contains(&ebb2), true);
            assert_eq!(ebb1_successors.contains(&ebb1), true);
            assert_eq!(ebb1_successors.contains(&ebb2), true);
        }

        // Change some instructions and recompute ebb0
        func.dfg.replace(br_ebb0_ebb2).brnz(cond, ebb1, &[]);
        func.dfg.replace(jmp_ebb0_ebb1).return_(&[]);
        cfg.recompute_ebb(&mut func, ebb0);
        let br_ebb0_ebb1 = br_ebb0_ebb2;

        {
            let ebb0_predecessors = cfg.get_predecessors(ebb0);
            let ebb1_predecessors = cfg.get_predecessors(ebb1);
            let ebb2_predecessors = cfg.get_predecessors(ebb2);

            let ebb0_successors = cfg.get_successors(ebb0);
            let ebb1_successors = cfg.get_successors(ebb1);
            let ebb2_successors = cfg.get_successors(ebb2);

            assert_eq!(ebb0_predecessors.len(), 0);
            assert_eq!(ebb1_predecessors.len(), 2);
            assert_eq!(ebb2_predecessors.len(), 1);

            assert_eq!(ebb1_predecessors.contains(&(ebb0, br_ebb0_ebb1)), true);
            assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
            assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), false);
            assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);

            assert_eq!(ebb0_successors.len(), 1);
            assert_eq!(ebb1_successors.len(), 2);
            assert_eq!(ebb2_successors.len(), 0);

            assert_eq!(ebb0_successors.contains(&ebb1), true);
            assert_eq!(ebb0_successors.contains(&ebb2), false);
            assert_eq!(ebb1_successors.contains(&ebb1), true);
            assert_eq!(ebb1_successors.contains(&ebb2), true);
        }
    }
}
<|endoftext|>