<commit_before>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => {},
            },
            None => {}
        }
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: &Command) {
        match command {
            &Command::Output => self.output(),
            &Command::Input => self.input(),
            &Command::Increment => self.increment(),
            &Command::Decrement => self.decrement(),
            &Command::RightShift => self.right_shift(),
            &Command::LeftShift => self.left_shift(),
        }
    }

    pub fn apply_many(&mut self, commands: &[Command]) {
        for command in commands {
            self.apply(&command)
        }
    }
}
<commit_msg>Panic on error in input<commit_after>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: &Command) {
        match command {
            &Command::Output => self.output(),
            &Command::Input => self.input(),
            &Command::Increment => self.increment(),
            &Command::Decrement => self.decrement(),
            &Command::RightShift => self.right_shift(),
            &Command::LeftShift => self.left_shift(),
        }
    }

    pub fn apply_many(&mut self, commands: &[Command]) {
        for command in commands {
            self.apply(&command)
        }
    }
}
<|endoftext|>


<commit_before>use time;
use chrono::prelude::Local;
use ansi_term::Colour;
use ansi_term::Colour::{Green, Red, Yellow};
use logger::Logger;

#[derive(PartialEq, Clone)]
pub enum TestCaseStatus {
    PASSED,
    FAILED,
    SKIPPED,
    UNKNOWN,
}

pub struct TestCase {
    pub title: &'static str,
    pub criteria: &'static str,
    pub exec: Box<Fn(&mut Logger) -> TestCaseStatus>,
}
impl TestCase {
    pub fn new(title: &'static str,
               criteria: &'static str,
               exec: Box<Fn(&mut Logger) -> TestCaseStatus>)
               -> TestCase {
        TestCase {
            title: title,
            criteria: criteria,
            exec: exec,
        }
    }
}

type DurationType = f64;

pub struct TestCaseResults {
    title: &'static str,
    criteria: &'static str,
    duration: DurationType,
    status: TestCaseStatus,
}

pub trait Testable {
    fn tests(self) -> Vec<TestCase>;
}

#[allow(dead_code)]
pub struct TestRunnerAttributes {
    pub bail_out_after_first_failure: i64,
    pub disable_final_stats:          i64,
    pub minimize_output:              i64,
    // more attributes can be added here
}

// attribute values need to be assigned here if new attributes are added to TestRunnerAttributes
pub static TEST_RUNNER_ATTRIBUTES: TestRunnerAttributes = TestRunnerAttributes {
    bail_out_after_first_failure: 0x1,
    disable_final_stats:          0x2,
    minimize_output:              0x4,
};

type TimeUnit = (i16, &'static str);

#[allow(dead_code)]
pub struct TestRunnerTimeUnits {
    pub minutes:      TimeUnit,
    pub seconds:      TimeUnit,
    pub milliseconds: TimeUnit,
    pub microseconds: TimeUnit,
    pub nanoseconds:  TimeUnit,
}

pub static TEST_RUNNER_TIME_UNITS: TestRunnerTimeUnits = TestRunnerTimeUnits {
    minutes:      (0x1, "min"),
    seconds:      (0x2, "sec"),
    milliseconds: (0x4, "ms"),
    microseconds: (0x8, "μs"),
    nanoseconds:  (0x10, "ns"),
};

#[allow(dead_code)]
pub struct TestRunner {
    attributes: i64,
    time_unit: TimeUnit,
    results: Vec<TestCaseResults>,
    module_path: &'static str,
}
impl TestRunner {
    pub fn new() -> TestRunner {
        TestRunner {
            attributes: 0,
            time_unit: TEST_RUNNER_TIME_UNITS.nanoseconds,
            results: vec![],
            module_path: "",
        }
    }
    pub fn set_module_path(&mut self, path: &'static str) -> &mut Self {
        self.module_path = path;
        self
    }
    pub fn set_attribute(&mut self, attribute: i64) -> &mut Self {
        self.attributes |= attribute;
        self
    }
    pub fn set_attributes(&mut self, attributes: i64) -> &mut Self {
        self.attributes = attributes;
        self
    }
    pub fn set_time_unit(&mut self, time_unit: TimeUnit) -> &mut Self {
        self.time_unit = time_unit;
        self
    }
    pub fn has_attribute(&self, attribute: i64) -> bool {
        self.attributes & attribute == attribute
    }
    pub fn run_test(&mut self, test: TestCase) -> bool {
        if !self.has_attribute(TEST_RUNNER_ATTRIBUTES.minimize_output) {
            println!("Starting {} at {} on {}",
                     test.title,
                     Local::now().format("%H:%M:%S").to_string(),
                     Local::now().format("%Y-%m-%d").to_string());
        }
        let mut logger: Logger = Logger::new();
        let starting_time: i32 = time::now().tm_nsec;
        let mut status: TestCaseStatus = (test.exec)(&mut logger);
        let ending_time: i32 = time::now().tm_nsec;
        if !self.has_attribute(TEST_RUNNER_ATTRIBUTES.minimize_output) {
            println!("Ended {} at {} on {}",
                     test.title,
                     Local::now().format("%H:%M:%S").to_string(),
                     Local::now().format("%Y-%m-%d").to_string());
            logger.drop();
        }
        if status == TestCaseStatus::UNKNOWN {
            if logger.get_num_fail() > 0 {
                status = TestCaseStatus::FAILED;
            } else {
                status = TestCaseStatus::PASSED;
            }
        }
        let mark = match status {
            TestCaseStatus::PASSED => "✅",
            TestCaseStatus::FAILED => "❌",
            TestCaseStatus::SKIPPED => "❗",
            TestCaseStatus::UNKNOWN => "",
        };
        let formatted_criteria = match status {
            TestCaseStatus::PASSED => Green.paint(test.criteria),
            TestCaseStatus::FAILED => Red.paint(test.criteria),
            TestCaseStatus::SKIPPED => Yellow.paint(test.criteria),
            TestCaseStatus::UNKNOWN => Yellow.paint(test.criteria),
        };
        let mut duration: DurationType = (ending_time - starting_time) as DurationType;
        if self.time_unit == TEST_RUNNER_TIME_UNITS.minutes {
            duration /= 1000000000 as DurationType;
            duration /= 60 as DurationType;
        }
        else if self.time_unit == TEST_RUNNER_TIME_UNITS.seconds {
            duration /= 1000000000 as DurationType;
        }
        else if self.time_unit == TEST_RUNNER_TIME_UNITS.milliseconds {
            duration /= 1000000 as DurationType;
        }
        else if self.time_unit == TEST_RUNNER_TIME_UNITS.microseconds {
            duration /= 1000 as DurationType;
        }
        let test_info = TestCaseResults {
            title: test.title,
            criteria: test.criteria,
            duration: duration,
            status: status.clone(),
        };
        if self.module_path.len() > 0 {
            println!("{} {}::{}: {} ({}{})", mark, self.module_path, test.title, formatted_criteria, test_info.duration, self.time_unit.1);
        }
        else {
            println!("{} {}: {} ({}{})", mark, test.title, formatted_criteria, test_info.duration, self.time_unit.1);
        }
        self.results.push(test_info);
        return status == TestCaseStatus::PASSED;
    }
    pub fn run_tests(&mut self, tests: Vec<TestCase>) -> bool {
        for test in tests {
            if !self.run_test(test) && self.has_attribute(TEST_RUNNER_ATTRIBUTES.bail_out_after_first_failure) {
                return false;
            }
        }
        return true;
    }
    pub fn run_tests_from_class<T: Testable>(&mut self, test_class: T) -> bool {
        return self.run_tests(test_class.tests());
    }
}
impl Drop for TestRunner {
    fn drop(&mut self) {
        if !self.has_attribute(TEST_RUNNER_ATTRIBUTES.disable_final_stats) {
            let (mut total_count, mut total_duration): (i32, DurationType) = (0, 0 as DurationType);
            let (mut pass, mut fail, mut skip): (i32, i32, i32) = (0, 0, 0);
            print!("\n");
            for stat in self.results.iter() {
                let color: Colour;
                match stat.status {
                    TestCaseStatus::PASSED => {
                        pass += 1;
                        color = Green;
                    },
                    TestCaseStatus::FAILED => {
                        fail += 1;
                        color = Red;
                    },
                    TestCaseStatus::SKIPPED => {
                        skip += 1;
                        color = Yellow;
                    },
                    _ => {
                        color = Yellow;
                    }
                };
                total_count += 1;
                total_duration += stat.duration;
                if self.module_path.len() > 0 {
                    println!("{}", color.paint(format!("{}::{}: {} ({}{})", self.module_path, stat.title, stat.criteria, stat.duration, self.time_unit.1)));
                }
                else {
                    println!("{}", color.paint(format!("{}: {} ({}{})", stat.title, stat.criteria, stat.duration, self.time_unit.1)));
                }

            }
            if total_count == 1 {
                println!("\nRan 1 test in {}{}", total_duration, self.time_unit.1);
            }
            else {
                println!("\nRan {} tests in {}{}", total_count, total_duration, self.time_unit.1);
            }
            let formatted_pass = Green.paint(format!("{} Passed", pass));
            let formatted_failed = Red.paint(format!("{} Failed", fail));
            let formatted_skipped = Yellow.paint(format!("{} Skipped", skip));
            println!("{}  {}  {}", formatted_pass, formatted_failed, formatted_skipped);
        }
    }
}
<commit_msg>set duration signficant digits output not to exceed 2 decimal places, but to not discard any whole unit precision.<commit_after>use time;
use chrono::prelude::Local;
use ansi_term::Colour;
use ansi_term::Colour::{Green, Red, Yellow};
use logger::Logger;

#[derive(PartialEq, Clone)]
pub enum TestCaseStatus {
    PASSED,
    FAILED,
    SKIPPED,
    UNKNOWN,
}

pub struct TestCase {
    pub title: &'static str,
    pub criteria: &'static str,
    pub exec: Box<Fn(&mut Logger) -> TestCaseStatus>,
}
impl TestCase {
    pub fn new(title: &'static str,
               criteria: &'static str,
               exec: Box<Fn(&mut Logger) -> TestCaseStatus>)
               -> TestCase {
        TestCase {
            title: title,
            criteria: criteria,
            exec: exec,
        }
    }
}

type DurationType = f64;

pub struct TestCaseResults {
    title: &'static str,
    criteria: &'static str,
    duration: DurationType,
    status: TestCaseStatus,
}

pub trait Testable {
    fn tests(self) -> Vec<TestCase>;
}

#[allow(dead_code)]
pub struct TestRunnerAttributes {
    pub bail_out_after_first_failure: i64,
    pub disable_final_stats:          i64,
    pub minimize_output:              i64,
    // more attributes can be added here
}

// attribute values need to be assigned here if new attributes are added to TestRunnerAttributes
pub static TEST_RUNNER_ATTRIBUTES: TestRunnerAttributes = TestRunnerAttributes {
    bail_out_after_first_failure: 0x1,
    disable_final_stats:          0x2,
    minimize_output:              0x4,
};

type TimeUnit = (i16, &'static str);

#[allow(dead_code)]
pub struct TestRunnerTimeUnits {
    pub minutes:      TimeUnit,
    pub seconds:      TimeUnit,
    pub milliseconds: TimeUnit,
    pub microseconds: TimeUnit,
    pub nanoseconds:  TimeUnit,
}

pub static TEST_RUNNER_TIME_UNITS: TestRunnerTimeUnits = TestRunnerTimeUnits {
    minutes:      (0x1, "min"),
    seconds:      (0x2, "sec"),
    milliseconds: (0x4, "ms"),
    microseconds: (0x8, "μs"),
    nanoseconds:  (0x10, "ns"),
};

#[allow(dead_code)]
pub struct TestRunner {
    attributes: i64,
    time_unit: TimeUnit,
    results: Vec<TestCaseResults>,
    module_path: &'static str,
}
impl TestRunner {
    pub fn new() -> TestRunner {
        TestRunner {
            attributes: 0,
            time_unit: TEST_RUNNER_TIME_UNITS.nanoseconds,
            results: vec![],
            module_path: "",
        }
    }
    pub fn set_module_path(&mut self, path: &'static str) -> &mut Self {
        self.module_path = path;
        self
    }
    pub fn set_attribute(&mut self, attribute: i64) -> &mut Self {
        self.attributes |= attribute;
        self
    }
    pub fn set_attributes(&mut self, attributes: i64) -> &mut Self {
        self.attributes = attributes;
        self
    }
    pub fn set_time_unit(&mut self, time_unit: TimeUnit) -> &mut Self {
        self.time_unit = time_unit;
        self
    }
    pub fn has_attribute(&self, attribute: i64) -> bool {
        self.attributes & attribute == attribute
    }
    pub fn run_test(&mut self, test: TestCase) -> bool {
        if !self.has_attribute(TEST_RUNNER_ATTRIBUTES.minimize_output) {
            println!("Starting {} at {} on {}",
                     test.title,
                     Local::now().format("%H:%M:%S").to_string(),
                     Local::now().format("%Y-%m-%d").to_string());
        }
        let mut logger: Logger = Logger::new();
        let starting_time: i32 = time::now().tm_nsec;
        let mut status: TestCaseStatus = (test.exec)(&mut logger);
        let ending_time: i32 = time::now().tm_nsec;
        if !self.has_attribute(TEST_RUNNER_ATTRIBUTES.minimize_output) {
            println!("Ended {} at {} on {}",
                     test.title,
                     Local::now().format("%H:%M:%S").to_string(),
                     Local::now().format("%Y-%m-%d").to_string());
            logger.drop();
        }
        if status == TestCaseStatus::UNKNOWN {
            if logger.get_num_fail() > 0 {
                status = TestCaseStatus::FAILED;
            } else {
                status = TestCaseStatus::PASSED;
            }
        }
        let mark = match status {
            TestCaseStatus::PASSED => "✅",
            TestCaseStatus::FAILED => "❌",
            TestCaseStatus::SKIPPED => "❗",
            TestCaseStatus::UNKNOWN => "",
        };
        let formatted_criteria = match status {
            TestCaseStatus::PASSED => Green.paint(test.criteria),
            TestCaseStatus::FAILED => Red.paint(test.criteria),
            TestCaseStatus::SKIPPED => Yellow.paint(test.criteria),
            TestCaseStatus::UNKNOWN => Yellow.paint(test.criteria),
        };
        let mut duration: DurationType = (ending_time - starting_time) as DurationType;
        if self.time_unit == TEST_RUNNER_TIME_UNITS.minutes {
            duration /= 1000000000 as DurationType;
            duration /= 60 as DurationType;
        }
        else if self.time_unit == TEST_RUNNER_TIME_UNITS.seconds {
            duration /= 1000000000 as DurationType;
        }
        else if self.time_unit == TEST_RUNNER_TIME_UNITS.milliseconds {
            duration /= 1000000 as DurationType;
        }
        else if self.time_unit == TEST_RUNNER_TIME_UNITS.microseconds {
            duration /= 1000 as DurationType;
        }
        let precision = match duration {
            _ if duration < 1.0 => 2_usize,
            _ if duration < 10.0 => 1_usize,
            _ => 0_usize,
        };
        let test_info = TestCaseResults {
            title: test.title,
            criteria: test.criteria,
            duration: duration,
            status: status.clone(),
        };
        if self.module_path.len() > 0 {
            println!("{} {}::{}: {} ({:.*}{})",mark, self.module_path, test.title, formatted_criteria, precision, test_info.duration, self.time_unit.1);
        }
        else {
            println!("{} {}: {} ({:.*}{})",mark, test.title, formatted_criteria, precision, test_info.duration, self.time_unit.1);
        }
        self.results.push(test_info);
        return status == TestCaseStatus::PASSED;
    }
    pub fn run_tests(&mut self, tests: Vec<TestCase>) -> bool {
        for test in tests {
            if !self.run_test(test) && self.has_attribute(TEST_RUNNER_ATTRIBUTES.bail_out_after_first_failure) {
                return false;
            }
        }
        return true;
    }
    pub fn run_tests_from_class<T: Testable>(&mut self, test_class: T) -> bool {
        return self.run_tests(test_class.tests());
    }
}
impl Drop for TestRunner {
    fn drop(&mut self) {
        if !self.has_attribute(TEST_RUNNER_ATTRIBUTES.disable_final_stats) {
            let (mut total_count, mut total_duration): (i32, DurationType) = (0, 0 as DurationType);
            let (mut pass, mut fail, mut skip): (i32, i32, i32) = (0, 0, 0);
            print!("\n");
            for stat in self.results.iter() {
                let color: Colour;
                match stat.status {
                    TestCaseStatus::PASSED => {
                        pass += 1;
                        color = Green;
                    },
                    TestCaseStatus::FAILED => {
                        fail += 1;
                        color = Red;
                    },
                    TestCaseStatus::SKIPPED => {
                        skip += 1;
                        color = Yellow;
                    },
                    _ => {
                        color = Yellow;
                    }
                };
                total_count += 1;
                total_duration += stat.duration;
                if self.module_path.len() > 0 {
                    println!("{}", color.paint(format!("{}::{}: {} ({}{})", self.module_path, stat.title, stat.criteria, stat.duration, self.time_unit.1)));
                }
                else {
                    println!("{}", color.paint(format!("{}: {} ({}{})", stat.title, stat.criteria, stat.duration, self.time_unit.1)));
                }

            }
            if total_count == 1 {
                println!("\nRan 1 test in {}{}", total_duration, self.time_unit.1);
            }
            else {
                println!("\nRan {} tests in {}{}", total_count, total_duration, self.time_unit.1);
            }
            let formatted_pass = Green.paint(format!("{} Passed", pass));
            let formatted_failed = Red.paint(format!("{} Failed", fail));
            let formatted_skipped = Yellow.paint(format!("{} Skipped", skip));
            println!("{}  {}  {}", formatted_pass, formatted_failed, formatted_skipped);
        }
    }
}
<|endoftext|>


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

//! The ChaCha random number generator.

use core::prelude::*;
use core::num::Int;

use {Rng, SeedableRng, Rand};

const KEY_WORDS    : uint =  8; // 8 words for the 256-bit key
const STATE_WORDS  : uint = 16;
const CHACHA_ROUNDS: uint = 20; // Cryptographically secure from 8 upwards as of this writing

/// A random number generator that uses the ChaCha20 algorithm [1].
///
/// The ChaCha algorithm is widely accepted as suitable for
/// cryptographic purposes, but this implementation has not been
/// verified as such. Prefer a generator like `OsRng` that defers to
/// the operating system for cases that need high security.
///
/// [1]: D. J. Bernstein, [*ChaCha, a variant of
/// Salsa20*](http://cr.yp.to/chacha.html)

#[deriving(Copy)]
pub struct ChaChaRng {
    buffer:  [u32, ..STATE_WORDS], // Internal buffer of output
    state:   [u32, ..STATE_WORDS], // Initial state
    index:   uint,                 // Index into state
}

static EMPTY: ChaChaRng = ChaChaRng {
    buffer:  [0, ..STATE_WORDS],
    state:   [0, ..STATE_WORDS],
    index:   STATE_WORDS
};

macro_rules! quarter_round{
    ($a: expr, $b: expr, $c: expr, $d: expr) => {{
        $a += $b; $d ^= $a; $d = $d.rotate_left(16);
        $c += $d; $b ^= $c; $b = $b.rotate_left(12);
        $a += $b; $d ^= $a; $d = $d.rotate_left( 8);
        $c += $d; $b ^= $c; $b = $b.rotate_left( 7);
    }}
}

macro_rules! double_round{
    ($x: expr) => {{
        // Column round
        quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]);
        quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]);
        quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]);
        quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]);
        // Diagonal round
        quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]);
        quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]);
        quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]);
        quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]);
    }}
}

#[inline]
fn core(output: &mut [u32, ..STATE_WORDS], input: &[u32, ..STATE_WORDS]) {
    *output = *input;

    for _ in range(0, CHACHA_ROUNDS / 2) {
        double_round!(output);
    }

    for i in range(0, STATE_WORDS) {
        output[i] += input[i];
    }
}

impl ChaChaRng {

    /// Create an ChaCha random number generator using the default
    /// fixed key of 8 zero words.
    pub fn new_unseeded() -> ChaChaRng {
        let mut rng = EMPTY;
        rng.init(&[0, ..KEY_WORDS]);
        rng
    }

    /// Sets the internal 128-bit ChaCha counter to
    /// a user-provided value. This permits jumping
    /// arbitrarily ahead (or backwards) in the pseudorandom stream.
    ///
    /// Since the nonce words are used to extend the counter to 128 bits,
    /// users wishing to obtain the conventional ChaCha pseudorandom stream
    /// associated with a particular nonce can call this function with
    /// arguments `0, desired_nonce`.
    pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
        self.state[12] = (counter_low >>  0) as u32;
        self.state[13] = (counter_low >> 32) as u32;
        self.state[14] = (counter_high >>  0) as u32;
        self.state[15] = (counter_high >> 32) as u32;
        self.index = STATE_WORDS; // force recomputation
    }

    /// Initializes `self.state` with the appropriate key and constants
    ///
    /// We deviate slightly from the ChaCha specification regarding
    /// the nonce, which is used to extend the counter to 128 bits.
    /// This is provably as strong as the original cipher, though,
    /// since any distinguishing attack on our variant also works
    /// against ChaCha with a chosen-nonce. See the XSalsa20 [1]
    /// security proof for a more involved example of this.
    ///
    /// The modified word layout is:
    /// ```text
    /// constant constant constant constant
    /// key      key      key      key
    /// key      key      key      key
    /// counter  counter  counter  counter
    /// ```
    /// [1]: Daniel J. Bernstein. [*Extending the Salsa20
    /// nonce.*](http://cr.yp.to/papers.html#xsalsa)
    fn init(&mut self, key: &[u32, ..KEY_WORDS]) {
        self.state[0] = 0x61707865;
        self.state[1] = 0x3320646E;
        self.state[2] = 0x79622D32;
        self.state[3] = 0x6B206574;

        for i in range(0, KEY_WORDS) {
            self.state[4+i] = key[i];
        }

        self.state[12] = 0;
        self.state[13] = 0;
        self.state[14] = 0;
        self.state[15] = 0;

        self.index = STATE_WORDS;
    }

    /// Refill the internal output buffer (`self.buffer`)
    fn update(&mut self) {
        core(&mut self.buffer, &self.state);
        self.index = 0;
        // update 128-bit counter
        self.state[12] += 1;
        if self.state[12] != 0 { return };
        self.state[13] += 1;
        if self.state[13] != 0 { return };
        self.state[14] += 1;
        if self.state[14] != 0 { return };
        self.state[15] += 1;
    }
}

impl Rng for ChaChaRng {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        if self.index == STATE_WORDS {
            self.update();
        }

        let value = self.buffer[self.index % STATE_WORDS];
        self.index += 1;
        value
    }
}

impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {

    fn reseed(&mut self, seed: &'a [u32]) {
        // reset state
        self.init(&[0u32, ..KEY_WORDS]);
        // set key in place
        let key = self.state.slice_mut(4, 4+KEY_WORDS);
        for (k, s) in key.iter_mut().zip(seed.iter()) {
            *k = *s;
        }
    }

    /// Create a ChaCha generator from a seed,
    /// obtained from a variable-length u32 array.
    /// Only up to 8 words are used; if less than 8
    /// words are used, the remaining are set to zero.
    fn from_seed(seed: &'a [u32]) -> ChaChaRng {
        let mut rng = EMPTY;
        rng.reseed(seed);
        rng
    }
}

impl Rand for ChaChaRng {
    fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
        let mut key : [u32, ..KEY_WORDS] = [0, ..KEY_WORDS];
        for word in key.iter_mut() {
            *word = other.gen();
        }
        SeedableRng::from_seed(key.as_slice())
    }
}

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

    use core::iter::order;
    use {Rng, SeedableRng};
    use super::ChaChaRng;

    #[test]
    fn test_rng_rand_seeded() {
        let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
        let mut ra: ChaChaRng = SeedableRng::from_seed(s.as_slice());
        let mut rb: ChaChaRng = SeedableRng::from_seed(s.as_slice());
        assert!(order::equals(ra.gen_ascii_chars().take(100),
                              rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_seeded() {
        let seed : &[_] = &[0,1,2,3,4,5,6,7];
        let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
        let mut rb: ChaChaRng = SeedableRng::from_seed(seed);
        assert!(order::equals(ra.gen_ascii_chars().take(100),
                              rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_reseed() {
        let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
        let mut r: ChaChaRng = SeedableRng::from_seed(s.as_slice());
        let string1: String = r.gen_ascii_chars().take(100).collect();

        r.reseed(s.as_slice());

        let string2: String = r.gen_ascii_chars().take(100).collect();
        assert_eq!(string1, string2);
    }

    #[test]
    fn test_rng_true_values() {
        // Test vectors 1 and 2 from
        // http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
        let seed : &[_] = &[0u32, ..8];
        let mut ra: ChaChaRng = SeedableRng::from_seed(seed);

        let v = Vec::from_fn(16, |_| ra.next_u32());
        assert_eq!(v,
                   vec!(0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653,
                        0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b,
                        0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8,
                        0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2));

        let v = Vec::from_fn(16, |_| ra.next_u32());
        assert_eq!(v,
                   vec!(0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73,
                        0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32,
                        0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874,
                        0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b));

        let seed : &[_] = &[0,1,2,3,4,5,6,7];
        let mut ra: ChaChaRng = SeedableRng::from_seed(seed);

        // Store the 17*i-th 32-bit word,
        // i.e., the i-th word of the i-th 16-word block
        let mut v : Vec<u32> = Vec::new();
        for _ in range(0u, 16) {
            v.push(ra.next_u32());
            for _ in range(0u, 16) {
                ra.next_u32();
            }
        }

        assert_eq!(v,
                   vec!(0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036,
                        0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384,
                        0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530,
                        0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4));
    }
}

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

//! The ChaCha random number generator.

use core::prelude::*;
use core::num::Int;

use {Rng, SeedableRng, Rand};

const KEY_WORDS    : uint =  8; // 8 words for the 256-bit key
const STATE_WORDS  : uint = 16;
const CHACHA_ROUNDS: uint = 20; // Cryptographically secure from 8 upwards as of this writing

/// A random number generator that uses the ChaCha20 algorithm [1].
///
/// The ChaCha algorithm is widely accepted as suitable for
/// cryptographic purposes, but this implementation has not been
/// verified as such. Prefer a generator like `OsRng` that defers to
/// the operating system for cases that need high security.
///
/// [1]: D. J. Bernstein, [*ChaCha, a variant of
/// Salsa20*](http://cr.yp.to/chacha.html)

#[deriving(Copy)]
pub struct ChaChaRng {
    buffer:  [u32, ..STATE_WORDS], // Internal buffer of output
    state:   [u32, ..STATE_WORDS], // Initial state
    index:   uint,                 // Index into state
}

static EMPTY: ChaChaRng = ChaChaRng {
    buffer:  [0, ..STATE_WORDS],
    state:   [0, ..STATE_WORDS],
    index:   STATE_WORDS
};

macro_rules! quarter_round{
    ($a: expr, $b: expr, $c: expr, $d: expr) => {{
        $a += $b; $d ^= $a; $d = $d.rotate_left(16);
        $c += $d; $b ^= $c; $b = $b.rotate_left(12);
        $a += $b; $d ^= $a; $d = $d.rotate_left( 8);
        $c += $d; $b ^= $c; $b = $b.rotate_left( 7);
    }}
}

macro_rules! double_round{
    ($x: expr) => {{
        // Column round
        quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]);
        quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]);
        quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]);
        quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]);
        // Diagonal round
        quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]);
        quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]);
        quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]);
        quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]);
    }}
}

#[inline]
fn core(output: &mut [u32, ..STATE_WORDS], input: &[u32, ..STATE_WORDS]) {
    *output = *input;

    for _ in range(0, CHACHA_ROUNDS / 2) {
        double_round!(output);
    }

    for i in range(0, STATE_WORDS) {
        output[i] += input[i];
    }
}

impl ChaChaRng {

    /// Create an ChaCha random number generator using the default
    /// fixed key of 8 zero words.
    pub fn new_unseeded() -> ChaChaRng {
        let mut rng = EMPTY;
        rng.init(&[0, ..KEY_WORDS]);
        rng
    }

    /// Sets the internal 128-bit ChaCha counter to
    /// a user-provided value. This permits jumping
    /// arbitrarily ahead (or backwards) in the pseudorandom stream.
    ///
    /// Since the nonce words are used to extend the counter to 128 bits,
    /// users wishing to obtain the conventional ChaCha pseudorandom stream
    /// associated with a particular nonce can call this function with
    /// arguments `0, desired_nonce`.
    pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
        self.state[12] = (counter_low >>  0) as u32;
        self.state[13] = (counter_low >> 32) as u32;
        self.state[14] = (counter_high >>  0) as u32;
        self.state[15] = (counter_high >> 32) as u32;
        self.index = STATE_WORDS; // force recomputation
    }

    /// Initializes `self.state` with the appropriate key and constants
    ///
    /// We deviate slightly from the ChaCha specification regarding
    /// the nonce, which is used to extend the counter to 128 bits.
    /// This is provably as strong as the original cipher, though,
    /// since any distinguishing attack on our variant also works
    /// against ChaCha with a chosen-nonce. See the XSalsa20 [1]
    /// security proof for a more involved example of this.
    ///
    /// The modified word layout is:
    /// ```text
    /// constant constant constant constant
    /// key      key      key      key
    /// key      key      key      key
    /// counter  counter  counter  counter
    /// ```
    /// [1]: Daniel J. Bernstein. [*Extending the Salsa20
    /// nonce.*](http://cr.yp.to/papers.html#xsalsa)
    fn init(&mut self, key: &[u32, ..KEY_WORDS]) {
        self.state[0] = 0x61707865;
        self.state[1] = 0x3320646E;
        self.state[2] = 0x79622D32;
        self.state[3] = 0x6B206574;

        for i in range(0, KEY_WORDS) {
            self.state[4+i] = key[i];
        }

        self.state[12] = 0;
        self.state[13] = 0;
        self.state[14] = 0;
        self.state[15] = 0;

        self.index = STATE_WORDS;
    }

    /// Refill the internal output buffer (`self.buffer`)
    fn update(&mut self) {
        core(&mut self.buffer, &self.state);
        self.index = 0;
        // update 128-bit counter
        self.state[12] += 1;
        if self.state[12] != 0 { return };
        self.state[13] += 1;
        if self.state[13] != 0 { return };
        self.state[14] += 1;
        if self.state[14] != 0 { return };
        self.state[15] += 1;
    }
}

impl Rng for ChaChaRng {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        if self.index == STATE_WORDS {
            self.update();
        }

        let value = self.buffer[self.index % STATE_WORDS];
        self.index += 1;
        value
    }
}

impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {

    fn reseed(&mut self, seed: &'a [u32]) {
        // reset state
        self.init(&[0u32, ..KEY_WORDS]);
        // set key in place
        let key = self.state.slice_mut(4, 4+KEY_WORDS);
        for (k, s) in key.iter_mut().zip(seed.iter()) {
            *k = *s;
        }
    }

    /// Create a ChaCha generator from a seed,
    /// obtained from a variable-length u32 array.
    /// Only up to 8 words are used; if less than 8
    /// words are used, the remaining are set to zero.
    fn from_seed(seed: &'a [u32]) -> ChaChaRng {
        let mut rng = EMPTY;
        rng.reseed(seed);
        rng
    }
}

impl Rand for ChaChaRng {
    fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
        let mut key : [u32, ..KEY_WORDS] = [0, ..KEY_WORDS];
        for word in key.iter_mut() {
            *word = other.gen();
        }
        SeedableRng::from_seed(key.as_slice())
    }
}

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

    use core::iter::order;
    use {Rng, SeedableRng};
    use super::ChaChaRng;

    #[test]
    fn test_rng_rand_seeded() {
        let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
        let mut ra: ChaChaRng = SeedableRng::from_seed(s.as_slice());
        let mut rb: ChaChaRng = SeedableRng::from_seed(s.as_slice());
        assert!(order::equals(ra.gen_ascii_chars().take(100),
                              rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_seeded() {
        let seed : &[_] = &[0,1,2,3,4,5,6,7];
        let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
        let mut rb: ChaChaRng = SeedableRng::from_seed(seed);
        assert!(order::equals(ra.gen_ascii_chars().take(100),
                              rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_reseed() {
        let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
        let mut r: ChaChaRng = SeedableRng::from_seed(s.as_slice());
        let string1: String = r.gen_ascii_chars().take(100).collect();

        r.reseed(s.as_slice());

        let string2: String = r.gen_ascii_chars().take(100).collect();
        assert_eq!(string1, string2);
    }

    #[test]
    fn test_rng_true_values() {
        // Test vectors 1 and 2 from
        // http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
        let seed : &[_] = &[0u32; 8];
        let mut ra: ChaChaRng = SeedableRng::from_seed(seed);

        let v = Vec::from_fn(16, |_| ra.next_u32());
        assert_eq!(v,
                   vec!(0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653,
                        0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b,
                        0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8,
                        0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2));

        let v = Vec::from_fn(16, |_| ra.next_u32());
        assert_eq!(v,
                   vec!(0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73,
                        0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32,
                        0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874,
                        0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b));

        let seed : &[_] = &[0,1,2,3,4,5,6,7];
        let mut ra: ChaChaRng = SeedableRng::from_seed(seed);

        // Store the 17*i-th 32-bit word,
        // i.e., the i-th word of the i-th 16-word block
        let mut v : Vec<u32> = Vec::new();
        for _ in range(0u, 16) {
            v.push(ra.next_u32());
            for _ in range(0u, 16) {
                ra.next_u32();
            }
        }

        assert_eq!(v,
                   vec!(0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036,
                        0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384,
                        0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530,
                        0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4));
    }
}

<|endoftext|>


<commit_before>use Prefab;
use calx::{hex_neighbors, Dijkstra, SRgba};
use euclid::vec2;
use form::{self, Form};
use image::{self, GenericImage, Pixel};
use location::{Location, Portal, Sector};
use mapgen::{self, DigCavesGen, Size2D};
use rand::{self, Rand, Rng, SeedableRng};
use serde;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::slice;
use terrain::Terrain;
use world::Loadout;

/// Static generated world.
pub struct Worldgen {
    seed: u32,
    terrain: HashMap<Location, Terrain>,
    portals: HashMap<Location, Portal>,
    spawns: Vec<(Location, Loadout)>,
    player_entry: Location,
}

impl Worldgen {
    pub fn new(seed: u32) -> Worldgen {
        let mut ret = Worldgen {
            seed: seed,
            terrain: HashMap::new(),
            portals: HashMap::new(),
            spawns: Vec::new(),
            player_entry: Location::new(0, 0, 0),
        };

        let mut rng: ::Rng = SeedableRng::from_seed([seed, seed, seed, seed]);

        let mut cave_entrance = Location::new(9, 0, 0);
        ret.cave_entrance(cave_entrance);
        ret.terrain
            .insert(cave_entrance + vec2(1, 1), Terrain::Gate);

        for depth in 1..11 {
            let up_stairs;
            let down_stairs;
            let mut spawns = Vec::new();

            {
                let mut digger = SectorDigger::new(&mut ret, Sector::new(0, 0, depth as i16));
                let gen = DigCavesGen::new(digger.domain());
                gen.dig(&mut rng, &mut digger);

                up_stairs = digger.up_portal.expect("Mapgen didn't create stairs up");
                down_stairs = digger
                    .down_portal
                    .expect("Mapgen didn't create stairs down");

                // Spawn
                digger.clear_spawns_near_entrance(12);

                let mut spawn_locs = rand::sample(&mut rng, digger.spawn_region.iter(), 20);
                let n_spawns = spawn_locs.len();

                let items = Form::filter(|f| f.is_item() && f.at_depth(depth));
                for &loc in spawn_locs.drain(0..n_spawns / 2) {
                    spawns.push((
                        loc,
                        form::rand(&mut rng, &items)
                            .expect("No item spawn")
                            .loadout
                            .clone(),
                    ))
                }

                let mobs = Form::filter(|f| f.is_mob() && f.at_depth(depth));
                for &loc in spawn_locs {
                    spawns.push((
                        loc,
                        form::rand(&mut rng, &mobs)
                            .expect("No mob spawn")
                            .loadout
                            .clone(),
                    ))
                }
            }

            ret.spawns.extend(spawns.into_iter());
            ret.portal(cave_entrance, up_stairs + vec2(1, 1));
            ret.portal(up_stairs, cave_entrance - vec2(1, 1));
            cave_entrance = down_stairs;

            // TODO: Generator needs an option to not generate stairs down on bottom level
        }

        ret
    }

    fn load_prefab(&mut self, origin: Location, prefab: &Prefab) {
        for (&p, &(ref terrain, ref entities)) in prefab.iter() {
            let loc = origin + p;

            self.terrain.insert(loc, *terrain);

            for spawn in entities.iter() {
                if spawn == "player" {
                    self.player_entry = loc;
                } else {
                    let form = Form::named(spawn)
                        .expect(&format!("Bad prefab: Form '{}' not found!", spawn));
                    self.spawns.push((loc, form.loadout.clone()));
                }
            }
        }
    }

    fn load_map_bitmap(&mut self, origin: Location, path: &str) {
        let image = image::open(path).unwrap();

        // Skip the bottom horizontal line, it's used to store metadata pixels.
        // (Currently using it to store palette pixels for the terrains to force image palette)
        for y in 0..(image.height() - 1) {
            for x in 0..image.width() {
                let loc = origin + vec2(x as i32, y as i32);
                let (r, g, b, _) = image.get_pixel(x, y).channels4();

                if let Some(terrain) = Terrain::from_color(SRgba::new(r, g, b, 0xff)) {
                    self.terrain.insert(loc, terrain);
                }
            }
        }
    }

    pub fn seed(&self) -> u32 { self.seed }

    pub fn get_terrain(&self, loc: Location) -> Terrain {
        if let Some(&t) = self.terrain.get(&loc) {
            t
        } else {
            self.default_terrain(loc)
        }
    }

    fn default_terrain(&self, loc: Location) -> Terrain {
        use Terrain::*;
        if loc.z == 0 {
            match loc.noise() {
                n if n > 0.8 => Tree,
                n if n > -0.8 => Grass,
                _ => Water,
            }
        } else {
            Terrain::Rock
        }
    }

    pub fn get_portal(&self, loc: Location) -> Option<Location> {
        self.portals.get(&loc).map(|&p| loc + p)
    }

    pub fn spawns(&self) -> slice::Iter<(Location, Loadout)> { self.spawns.iter() }

    pub fn player_entry(&self) -> Location { self.player_entry }

    /// Make a cave entrance going down.
    fn cave_entrance(&mut self, loc: Location) {
        const DOWNBOUND_ENCLOSURE: [(i32, i32); 5] = [(1, 0), (0, 1), (2, 1), (1, 2), (2, 2)];

        for &v in &DOWNBOUND_ENCLOSURE {
            let loc = loc + vec2(v.0, v.1);
            self.terrain.insert(loc, Terrain::Rock);
        }

        self.terrain.insert(loc, Terrain::Ground);
        self.terrain.insert(loc + vec2(1, 1), Terrain::Ground);
    }

    /// Punch a (one-way) portal between two points.
    fn portal(&mut self, origin: Location, destination: Location) {
        self.portals
            .insert(origin, Portal::new(origin, destination));
    }
}

impl serde::Serialize for Worldgen {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.seed.serialize(s)
    }
}

impl<'a> serde::Deserialize<'a> for Worldgen {
    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
        Ok(Worldgen::new(serde::Deserialize::deserialize(d)?))
    }
}

struct SectorDigger<'a> {
    worldgen: &'a mut Worldgen,
    sector: Sector,
    up_portal: Option<Location>,
    down_portal: Option<Location>,
    spawn_region: BTreeSet<Location>,
}

impl<'a> SectorDigger<'a> {
    fn new(worldgen: &'a mut Worldgen, sector: Sector) -> SectorDigger<'a> {
        SectorDigger {
            worldgen,
            sector,
            up_portal: None,
            down_portal: None,
            spawn_region: BTreeSet::new(),
        }
    }

    // TODO return impl
    fn domain(&self) -> Vec<mapgen::Point2D> {
        let mut ret = Vec::new();

        let sector_origin = self.sector.origin();
        let mapgen_origin = mapgen::Point2D::zero();

        for loc in self.sector.iter() {
            let pos = mapgen_origin
                + sector_origin
                    .v2_at(loc)
                    .expect("Sector points are not Euclidean");

            // Okay, this part is a bit hairy, hang on.
            // Sectors are arranged in a rectangular grid, so there are some cells where you can
            // step diagonally across two sector boundaries. However, we want to pretend that
            // sectors are only connected in the four cardinal directions, so we omit these cells
            // from the domain to prevent surprise holes between two diagonally adjacent shafts.
            if Self::is_next_to_diagonal_sector(loc) {
                continue;
            }

            ret.push(pos);
        }

        ret
    }

    fn loc(&self, pos: mapgen::Point2D) -> Location { self.sector.origin() + pos.to_vector() }

    fn set(&mut self, loc: Location, terrain: Terrain) {
        if terrain != Terrain::Gate {
            debug_assert_ne!(self.up_portal, Some(loc), "mapgen overwriting exit");
            debug_assert_ne!(self.down_portal, Some(loc), "mapgen overwriting exit");
        }

        // FIXME: Mapgen currently trips this with exit placement
        // debug_assert!(
        //     !Self::is_next_to_diagonal_sector(loc) &&
        //     self.sector.iter().find(|x| x == &loc).is_some(),
        //     "Setting a location outsides sector area");

        self.worldgen.terrain.insert(loc, terrain);
    }

    fn clear_spawns_near_entrance(&mut self, range: u32) {
        for loc in Dijkstra::new(
            vec![self.up_portal.expect("No entrance generated")],
            |loc| {
                self.worldgen
                    .terrain
                    .get(loc)
                    .cloned()
                    .unwrap_or(Terrain::Empty)
                    .is_open()
            },
            10_000,
        ).weights
            .iter()
            .filter_map(|(loc, &w)| if w <= range { Some(loc) } else { None })
        {
            self.spawn_region.remove(loc);
        }
    }

    fn is_next_to_diagonal_sector(loc: Location) -> bool {
        hex_neighbors(loc)
            .map(|x| x.sector().taxicab_distance(loc.sector()))
            .any(|d| d > 1)
    }
}

impl<'a> mapgen::Dungeon for SectorDigger<'a> {
    type Prefab = Room;

    /// Return a random prefab room.
    fn sample_prefab<R: Rng>(&mut self, rng: &mut R) -> Self::Prefab { rng.gen() }

    /// Add a large open continuous region to dungeon.
    fn dig_chamber<I: IntoIterator<Item = mapgen::Point2D>>(&mut self, area: I) {
        for pos in area {
            let loc = self.loc(pos);
            self.spawn_region.insert(loc);
            self.set(loc, Terrain::Ground);
        }
    }

    /// Add a narrow corridor to dungeon.
    fn dig_corridor<I: IntoIterator<Item = mapgen::Point2D>>(&mut self, path: I) {
        for pos in path {
            let loc = self.loc(pos);
            // Do not spawn things in corridors.
            self.spawn_region.remove(&loc);
            self.set(loc, Terrain::Ground);
        }
    }

    fn add_prefab(&mut self, prefab: &Self::Prefab, pos: mapgen::Point2D) {
        // TODO
        unimplemented!();
    }

    fn add_door(&mut self, pos: mapgen::Point2D) {
        let loc = self.loc(pos);
        self.spawn_region.remove(&loc);
        self.set(loc, Terrain::Door);
    }

    fn add_up_stairs(&mut self, pos: mapgen::Point2D) {
        let loc = self.loc(pos);
        self.up_portal = Some(loc);
        self.spawn_region.remove(&loc);
        // TODO: Add debug assertion that up-stairs are dug in the upper wall of a room
        self.set(loc, Terrain::Gate);
    }

    fn add_down_stairs(&mut self, pos: mapgen::Point2D) {
        let loc = self.loc(pos);
        self.down_portal = Some(loc);
        self.spawn_region.remove(&loc);
        self.set(loc, Terrain::Gate);

        // Visual hack to make the down-stairs show up better, carve out the rock blob that would
        // be drawn partially in front of it on screen.
        self.set(loc + vec2(1, 1), Terrain::Empty);
        // TODO: Add a debug assertion here to check that the exit location has proper enclosure to
        // begin with, both it and the rock cell in front of it need to be surrounded by undug
        // front tiles.
        self.spawn_region.remove(&(loc + vec2(1, 1))); // Just in case
    }
}

struct Room {
    size: Size2D,
}

impl mapgen::Prefab for Room {
    fn contains(&self, pos: mapgen::Point2D) -> bool {
        pos.x >= 0 && pos.y >= 0 && pos.x < self.size.width && pos.y < self.size.height
    }

    fn can_make_door(&self, pos: mapgen::Point2D) -> bool {
        let on_x_wall = pos.x == 0 || pos.x == self.size.width - 1;
        let on_y_wall = pos.y == 0 || pos.y == self.size.height - 1;

        // Must touch one wall, but touching both makes it a corner and we don't want rooms there.
        on_x_wall ^ on_y_wall
    }

    fn size(&self) -> Size2D { self.size }
}

impl Rand for Room {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        Room {
            size: Size2D::new(rng.gen_range(3, 10), rng.gen_range(3, 10)),
        }
    }
}

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

    #[test]
    fn test_determinism() {
        use rand::{self, Rand};

        let mut rng = rand::thread_rng();

        let seed = u32::rand(&mut rng);
        let mut gen = Worldgen::new(seed);

        // Build the value repeatedly using the same seed and see that they are all equal.
        for _ in 1..4 {
            let second = Worldgen::new(seed);

            assert_eq!(gen.seed, second.seed);
            // These can make huge printouts so don't use assert_eq that would try to print them to
            // stdout
            assert!(gen.terrain == second.terrain);
            assert!(gen.portals == second.portals);
            assert_eq!(gen.player_entry, second.player_entry);

            gen = second;
        }
    }
}
<commit_msg>Test overland map in worldgen<commit_after>use Prefab;
use calx::{hex_neighbors, Dijkstra, SRgba};
use euclid::vec2;
use form::{self, Form};
use image::{self, GenericImage, Pixel};
use location::{Location, Portal, Sector};
use mapgen::{self, DigCavesGen, Size2D};
use rand::{self, Rand, Rng, SeedableRng};
use serde;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::slice;
use terrain::Terrain;
use world::Loadout;

/// Static generated world.
pub struct Worldgen {
    seed: u32,
    terrain: HashMap<Location, Terrain>,
    portals: HashMap<Location, Portal>,
    spawns: Vec<(Location, Loadout)>,
    player_entry: Location,
}

impl Worldgen {
    pub fn new(seed: u32) -> Worldgen {
        let mut ret = Worldgen {
            seed: seed,
            terrain: HashMap::new(),
            portals: HashMap::new(),
            spawns: Vec::new(),
            player_entry: Location::new(157, 21, 0),
        };

        let mut rng: ::Rng = SeedableRng::from_seed([seed, seed, seed, seed]);

        let mut cave_entrance = Location::new(9, 0, 0);
        ret.cave_entrance(cave_entrance);
        ret.terrain
            .insert(cave_entrance + vec2(1, 1), Terrain::Gate);

        for depth in 1..11 {
            let up_stairs;
            let down_stairs;
            let mut spawns = Vec::new();

            {
                let mut digger = SectorDigger::new(&mut ret, Sector::new(0, 0, depth as i16));
                let gen = DigCavesGen::new(digger.domain());
                gen.dig(&mut rng, &mut digger);

                up_stairs = digger.up_portal.expect("Mapgen didn't create stairs up");
                down_stairs = digger
                    .down_portal
                    .expect("Mapgen didn't create stairs down");

                // Spawn
                digger.clear_spawns_near_entrance(12);

                let mut spawn_locs = rand::sample(&mut rng, digger.spawn_region.iter(), 20);
                let n_spawns = spawn_locs.len();

                let items = Form::filter(|f| f.is_item() && f.at_depth(depth));
                for &loc in spawn_locs.drain(0..n_spawns / 2) {
                    spawns.push((
                        loc,
                        form::rand(&mut rng, &items)
                            .expect("No item spawn")
                            .loadout
                            .clone(),
                    ))
                }

                let mobs = Form::filter(|f| f.is_mob() && f.at_depth(depth));
                for &loc in spawn_locs {
                    spawns.push((
                        loc,
                        form::rand(&mut rng, &mobs)
                            .expect("No mob spawn")
                            .loadout
                            .clone(),
                    ))
                }
            }

            ret.spawns.extend(spawns.into_iter());
            ret.portal(cave_entrance, up_stairs + vec2(1, 1));
            ret.portal(up_stairs, cave_entrance - vec2(1, 1));
            cave_entrance = down_stairs;

            // TODO: Generator needs an option to not generate stairs down on bottom level
        }

        ret.load_map_bitmap(Location::new(0, -199, 0), "overland.png");

        ret
    }

    fn load_prefab(&mut self, origin: Location, prefab: &Prefab) {
        for (&p, &(ref terrain, ref entities)) in prefab.iter() {
            let loc = origin + p;

            self.terrain.insert(loc, *terrain);

            for spawn in entities.iter() {
                if spawn == "player" {
                    self.player_entry = loc;
                } else {
                    let form = Form::named(spawn)
                        .expect(&format!("Bad prefab: Form '{}' not found!", spawn));
                    self.spawns.push((loc, form.loadout.clone()));
                }
            }
        }
    }

    fn load_map_bitmap(&mut self, origin: Location, path: &str) {
        let image = image::open(path).unwrap();

        // Skip the bottom horizontal line, it's used to store metadata pixels.
        // (Currently using it to store palette pixels for the terrains to force image palette)
        for y in 0..(image.height() - 1) {
            for x in 0..image.width() {
                let loc = origin + vec2(x as i32, y as i32);
                let (r, g, b, _) = image.get_pixel(x, y).channels4();

                if let Some(terrain) = Terrain::from_color(SRgba::new(r, g, b, 0xff)) {
                    self.terrain.insert(loc, terrain);
                }
            }
        }
    }

    pub fn seed(&self) -> u32 { self.seed }

    pub fn get_terrain(&self, loc: Location) -> Terrain {
        if let Some(&t) = self.terrain.get(&loc) {
            t
        } else {
            self.default_terrain(loc)
        }
    }

    fn default_terrain(&self, loc: Location) -> Terrain {
        use Terrain::*;
        if loc.z == 0 {
            /*
            match loc.noise() {
                n if n > 0.8 => Tree,
                n if n > -0.8 => Grass,
                _ => Water,
            }
            */
            Ground
        } else {
            Rock
        }
    }

    pub fn get_portal(&self, loc: Location) -> Option<Location> {
        self.portals.get(&loc).map(|&p| loc + p)
    }

    pub fn spawns(&self) -> slice::Iter<(Location, Loadout)> { self.spawns.iter() }

    pub fn player_entry(&self) -> Location { self.player_entry }

    /// Make a cave entrance going down.
    fn cave_entrance(&mut self, loc: Location) {
        const DOWNBOUND_ENCLOSURE: [(i32, i32); 5] = [(1, 0), (0, 1), (2, 1), (1, 2), (2, 2)];

        for &v in &DOWNBOUND_ENCLOSURE {
            let loc = loc + vec2(v.0, v.1);
            self.terrain.insert(loc, Terrain::Rock);
        }

        self.terrain.insert(loc, Terrain::Ground);
        self.terrain.insert(loc + vec2(1, 1), Terrain::Ground);
    }

    /// Punch a (one-way) portal between two points.
    fn portal(&mut self, origin: Location, destination: Location) {
        self.portals
            .insert(origin, Portal::new(origin, destination));
    }
}

impl serde::Serialize for Worldgen {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.seed.serialize(s)
    }
}

impl<'a> serde::Deserialize<'a> for Worldgen {
    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
        Ok(Worldgen::new(serde::Deserialize::deserialize(d)?))
    }
}

struct SectorDigger<'a> {
    worldgen: &'a mut Worldgen,
    sector: Sector,
    up_portal: Option<Location>,
    down_portal: Option<Location>,
    spawn_region: BTreeSet<Location>,
}

impl<'a> SectorDigger<'a> {
    fn new(worldgen: &'a mut Worldgen, sector: Sector) -> SectorDigger<'a> {
        SectorDigger {
            worldgen,
            sector,
            up_portal: None,
            down_portal: None,
            spawn_region: BTreeSet::new(),
        }
    }

    // TODO return impl
    fn domain(&self) -> Vec<mapgen::Point2D> {
        let mut ret = Vec::new();

        let sector_origin = self.sector.origin();
        let mapgen_origin = mapgen::Point2D::zero();

        for loc in self.sector.iter() {
            let pos = mapgen_origin
                + sector_origin
                    .v2_at(loc)
                    .expect("Sector points are not Euclidean");

            // Okay, this part is a bit hairy, hang on.
            // Sectors are arranged in a rectangular grid, so there are some cells where you can
            // step diagonally across two sector boundaries. However, we want to pretend that
            // sectors are only connected in the four cardinal directions, so we omit these cells
            // from the domain to prevent surprise holes between two diagonally adjacent shafts.
            if Self::is_next_to_diagonal_sector(loc) {
                continue;
            }

            ret.push(pos);
        }

        ret
    }

    fn loc(&self, pos: mapgen::Point2D) -> Location { self.sector.origin() + pos.to_vector() }

    fn set(&mut self, loc: Location, terrain: Terrain) {
        if terrain != Terrain::Gate {
            debug_assert_ne!(self.up_portal, Some(loc), "mapgen overwriting exit");
            debug_assert_ne!(self.down_portal, Some(loc), "mapgen overwriting exit");
        }

        // FIXME: Mapgen currently trips this with exit placement
        // debug_assert!(
        //     !Self::is_next_to_diagonal_sector(loc) &&
        //     self.sector.iter().find(|x| x == &loc).is_some(),
        //     "Setting a location outsides sector area");

        self.worldgen.terrain.insert(loc, terrain);
    }

    fn clear_spawns_near_entrance(&mut self, range: u32) {
        for loc in Dijkstra::new(
            vec![self.up_portal.expect("No entrance generated")],
            |loc| {
                self.worldgen
                    .terrain
                    .get(loc)
                    .cloned()
                    .unwrap_or(Terrain::Empty)
                    .is_open()
            },
            10_000,
        ).weights
            .iter()
            .filter_map(|(loc, &w)| if w <= range { Some(loc) } else { None })
        {
            self.spawn_region.remove(loc);
        }
    }

    fn is_next_to_diagonal_sector(loc: Location) -> bool {
        hex_neighbors(loc)
            .map(|x| x.sector().taxicab_distance(loc.sector()))
            .any(|d| d > 1)
    }
}

impl<'a> mapgen::Dungeon for SectorDigger<'a> {
    type Prefab = Room;

    /// Return a random prefab room.
    fn sample_prefab<R: Rng>(&mut self, rng: &mut R) -> Self::Prefab { rng.gen() }

    /// Add a large open continuous region to dungeon.
    fn dig_chamber<I: IntoIterator<Item = mapgen::Point2D>>(&mut self, area: I) {
        for pos in area {
            let loc = self.loc(pos);
            self.spawn_region.insert(loc);
            self.set(loc, Terrain::Ground);
        }
    }

    /// Add a narrow corridor to dungeon.
    fn dig_corridor<I: IntoIterator<Item = mapgen::Point2D>>(&mut self, path: I) {
        for pos in path {
            let loc = self.loc(pos);
            // Do not spawn things in corridors.
            self.spawn_region.remove(&loc);
            self.set(loc, Terrain::Ground);
        }
    }

    fn add_prefab(&mut self, prefab: &Self::Prefab, pos: mapgen::Point2D) {
        // TODO
        unimplemented!();
    }

    fn add_door(&mut self, pos: mapgen::Point2D) {
        let loc = self.loc(pos);
        self.spawn_region.remove(&loc);
        self.set(loc, Terrain::Door);
    }

    fn add_up_stairs(&mut self, pos: mapgen::Point2D) {
        let loc = self.loc(pos);
        self.up_portal = Some(loc);
        self.spawn_region.remove(&loc);
        // TODO: Add debug assertion that up-stairs are dug in the upper wall of a room
        self.set(loc, Terrain::Gate);
    }

    fn add_down_stairs(&mut self, pos: mapgen::Point2D) {
        let loc = self.loc(pos);
        self.down_portal = Some(loc);
        self.spawn_region.remove(&loc);
        self.set(loc, Terrain::Gate);

        // Visual hack to make the down-stairs show up better, carve out the rock blob that would
        // be drawn partially in front of it on screen.
        self.set(loc + vec2(1, 1), Terrain::Empty);
        // TODO: Add a debug assertion here to check that the exit location has proper enclosure to
        // begin with, both it and the rock cell in front of it need to be surrounded by undug
        // front tiles.
        self.spawn_region.remove(&(loc + vec2(1, 1))); // Just in case
    }
}

struct Room {
    size: Size2D,
}

impl mapgen::Prefab for Room {
    fn contains(&self, pos: mapgen::Point2D) -> bool {
        pos.x >= 0 && pos.y >= 0 && pos.x < self.size.width && pos.y < self.size.height
    }

    fn can_make_door(&self, pos: mapgen::Point2D) -> bool {
        let on_x_wall = pos.x == 0 || pos.x == self.size.width - 1;
        let on_y_wall = pos.y == 0 || pos.y == self.size.height - 1;

        // Must touch one wall, but touching both makes it a corner and we don't want rooms there.
        on_x_wall ^ on_y_wall
    }

    fn size(&self) -> Size2D { self.size }
}

impl Rand for Room {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        Room {
            size: Size2D::new(rng.gen_range(3, 10), rng.gen_range(3, 10)),
        }
    }
}

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

    #[test]
    fn test_determinism() {
        use rand::{self, Rand};

        let mut rng = rand::thread_rng();

        let seed = u32::rand(&mut rng);
        let mut gen = Worldgen::new(seed);

        // Build the value repeatedly using the same seed and see that they are all equal.
        for _ in 1..4 {
            let second = Worldgen::new(seed);

            assert_eq!(gen.seed, second.seed);
            // These can make huge printouts so don't use assert_eq that would try to print them to
            // stdout
            assert!(gen.terrain == second.terrain);
            assert!(gen.portals == second.portals);
            assert_eq!(gen.player_entry, second.player_entry);

            gen = second;
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::fs::Permissions;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=build/glslangValidator");
    println!("cargo:rerun-if-changed=build/glslangValidator.exe");

    let target = env::var("TARGET").unwrap();
    let out_file = Path::new(&env::var("OUT_DIR").unwrap()).join("glslang_validator");

    let path = if target.contains("windows") {
        Path::new("build/glslangValidator.exe")
    } else if target.contains("linux") {
        Path::new("build/glslangValidator")
    } else {
        panic!("The platform `{}` is not supported", target);
    };

    if let Err(_) = fs::hard_link(&path, &out_file) {
        fs::copy(&path, &out_file).unwrap();
    }

    // TODO: check the hash of the files to make sure that they are not altered

    // setting permissions of the executable
    {
        #[cfg(unix)] fn permissions() -> Option<Permissions> {
            use std::os::unix::fs::PermissionsExt;
            Some(Permissions::from_mode(755))
        }
        #[cfg(not(unix))] fn permissions() -> Option<Permissions> { None }
        if let Some(permissions) = permissions() {
            fs::set_permissions(&out_file, permissions).unwrap();
        }
    }
}
<commit_msg>Add error messages in case of problem in build script<commit_after>use std::env;
use std::fs;
use std::fs::Permissions;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=build/glslangValidator");
    println!("cargo:rerun-if-changed=build/glslangValidator.exe");

    let target = env::var("TARGET").unwrap();
    let out_file = Path::new(&env::var("OUT_DIR").unwrap()).join("glslang_validator");

    let path = if target.contains("windows") {
        Path::new("build/glslangValidator.exe")
    } else if target.contains("linux") {
        Path::new("build/glslangValidator")
    } else {
        panic!("The platform `{}` is not supported", target);
    };

    if let Err(_) = fs::hard_link(&path, &out_file) {
        fs::copy(&path, &out_file).expect("failed to copy executable");
    }

    // TODO: check the hash of the files to make sure that they are not altered

    // setting permissions of the executable
    {
        #[cfg(unix)] fn permissions() -> Option<Permissions> {
            use std::os::unix::fs::PermissionsExt;
            Some(Permissions::from_mode(755))
        }
        #[cfg(not(unix))] fn permissions() -> Option<Permissions> { None }
        if let Some(permissions) = permissions() {
            fs::set_permissions(&out_file, permissions).expect("failed to set permissions");
        }
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(any(not(feature = "full"), loom), allow(unused_imports, dead_code))]

mod atomic_ptr;
mod atomic_u16;
mod atomic_u32;
mod atomic_u64;
mod atomic_u8;
mod atomic_usize;
mod unsafe_cell;

pub(crate) mod cell {
    pub(crate) use super::unsafe_cell::UnsafeCell;
}

#[cfg(any(feature = "sync", feature = "io-driver"))]
pub(crate) mod future {
    pub(crate) use crate::sync::AtomicWaker;
}

pub(crate) mod rand {
    use std::collections::hash_map::RandomState;
    use std::hash::{BuildHasher, Hash, Hasher};
    use std::sync::atomic::AtomicU32;
    use std::sync::atomic::Ordering::Relaxed;

    static COUNTER: AtomicU32 = AtomicU32::new(1);

    pub(crate) fn seed() -> u64 {
        let rand_state = RandomState::new();

        let mut hasher = rand_state.build_hasher();

        // Hash some unique-ish data to generate some new state
        COUNTER.fetch_add(1, Relaxed).hash(&mut hasher);

        // Get the seed
        hasher.finish()
    }
}

pub(crate) mod sync {
    pub(crate) use std::sync::Arc;

    #[cfg(feature = "parking_lot")]
    mod pl_wrappers;

    // Below, make sure all the feature-influenced types are exported for
    // internal use. Note however that some are not _currently_ named by
    // consuming code.

    #[cfg(feature = "parking_lot")]
    #[allow(unused_imports)]
    pub(crate) use pl_wrappers::{Condvar, Mutex};

    #[cfg(feature = "parking_lot")]
    #[allow(unused_imports)]
    pub(crate) use parking_lot::{MutexGuard, WaitTimeoutResult};

    #[cfg(not(feature = "parking_lot"))]
    #[allow(unused_imports)]
    pub(crate) use std::sync::{Condvar, Mutex, MutexGuard, WaitTimeoutResult};

    pub(crate) mod atomic {
        pub(crate) use crate::loom::std::atomic_ptr::AtomicPtr;
        pub(crate) use crate::loom::std::atomic_u16::AtomicU16;
        pub(crate) use crate::loom::std::atomic_u32::AtomicU32;
        pub(crate) use crate::loom::std::atomic_u64::AtomicU64;
        pub(crate) use crate::loom::std::atomic_u8::AtomicU8;
        pub(crate) use crate::loom::std::atomic_usize::AtomicUsize;

        pub(crate) use std::sync::atomic::{spin_loop_hint, AtomicBool};
    }
}

pub(crate) mod sys {
    #[cfg(feature = "rt-threaded")]
    pub(crate) fn num_cpus() -> usize {
        usize::max(1, num_cpus::get_physical())
    }

    #[cfg(not(feature = "rt-threaded"))]
    pub(crate) fn num_cpus() -> usize {
        1
    }
}

pub(crate) use std::thread;
<commit_msg>Use logical CPUs instead of physical by default (#2391)<commit_after>#![cfg_attr(any(not(feature = "full"), loom), allow(unused_imports, dead_code))]

mod atomic_ptr;
mod atomic_u16;
mod atomic_u32;
mod atomic_u64;
mod atomic_u8;
mod atomic_usize;
mod unsafe_cell;

pub(crate) mod cell {
    pub(crate) use super::unsafe_cell::UnsafeCell;
}

#[cfg(any(feature = "sync", feature = "io-driver"))]
pub(crate) mod future {
    pub(crate) use crate::sync::AtomicWaker;
}

pub(crate) mod rand {
    use std::collections::hash_map::RandomState;
    use std::hash::{BuildHasher, Hash, Hasher};
    use std::sync::atomic::AtomicU32;
    use std::sync::atomic::Ordering::Relaxed;

    static COUNTER: AtomicU32 = AtomicU32::new(1);

    pub(crate) fn seed() -> u64 {
        let rand_state = RandomState::new();

        let mut hasher = rand_state.build_hasher();

        // Hash some unique-ish data to generate some new state
        COUNTER.fetch_add(1, Relaxed).hash(&mut hasher);

        // Get the seed
        hasher.finish()
    }
}

pub(crate) mod sync {
    pub(crate) use std::sync::Arc;

    #[cfg(feature = "parking_lot")]
    mod pl_wrappers;

    // Below, make sure all the feature-influenced types are exported for
    // internal use. Note however that some are not _currently_ named by
    // consuming code.

    #[cfg(feature = "parking_lot")]
    #[allow(unused_imports)]
    pub(crate) use pl_wrappers::{Condvar, Mutex};

    #[cfg(feature = "parking_lot")]
    #[allow(unused_imports)]
    pub(crate) use parking_lot::{MutexGuard, WaitTimeoutResult};

    #[cfg(not(feature = "parking_lot"))]
    #[allow(unused_imports)]
    pub(crate) use std::sync::{Condvar, Mutex, MutexGuard, WaitTimeoutResult};

    pub(crate) mod atomic {
        pub(crate) use crate::loom::std::atomic_ptr::AtomicPtr;
        pub(crate) use crate::loom::std::atomic_u16::AtomicU16;
        pub(crate) use crate::loom::std::atomic_u32::AtomicU32;
        pub(crate) use crate::loom::std::atomic_u64::AtomicU64;
        pub(crate) use crate::loom::std::atomic_u8::AtomicU8;
        pub(crate) use crate::loom::std::atomic_usize::AtomicUsize;

        pub(crate) use std::sync::atomic::{spin_loop_hint, AtomicBool};
    }
}

pub(crate) mod sys {
    #[cfg(feature = "rt-threaded")]
    pub(crate) fn num_cpus() -> usize {
        usize::max(1, num_cpus::get())
    }

    #[cfg(not(feature = "rt-threaded"))]
    pub(crate) fn num_cpus() -> usize {
        1
    }
}

pub(crate) use std::thread;
<|endoftext|>


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

use gpu_store::GpuStoreAddress;
use prim_store::{ClipData, GpuBlock32, PrimitiveStore};
use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
use renderer::VertexDataStore;
use util::{MatrixHelpers, TransformedRect};
use webrender_traits::{AuxiliaryLists, BorderRadius, ClipRegion, ComplexClipRegion, ImageMask};
use webrender_traits::{DeviceIntRect, LayerToWorldTransform};
use webrender_traits::{LayerRect, LayerPoint, LayerSize};

const MAX_CLIP: f32 = 1000000.0;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ClipMode {
    Clip,           // Pixels inside the region are visible.
    ClipOut,        // Pixels outside the region are visible.
}

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RegionMode {
    IncludeRect,
    ExcludeRect,
}

#[derive(Clone, Debug)]
pub enum ClipSource {
    Complex(LayerRect, f32, ClipMode),
    // The RegionMode here specifies whether to consider the rect
    // from the clip region as part of the mask. This is true
    // for clip/scroll nodes, but false for primitives, where
    // the clip rect is handled in local space.
    Region(ClipRegion, RegionMode),
}

impl ClipSource {
    pub fn image_mask(&self) -> Option<ImageMask> {
        match self {
            &ClipSource::Complex(..) => None,
            &ClipSource::Region(ref region, _) => region.image_mask,
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ClipAddressRange {
    pub start: GpuStoreAddress,
    item_count: usize,
}

/// Represents a local rect and a device space
/// bounding rect that can be updated when the
/// transform changes.
#[derive(Clone, Debug, PartialEq)]
pub struct Geometry {
    pub local_rect: LayerRect,
    pub bounding_rect: DeviceIntRect,
}

impl Geometry {
    fn new(local_rect: LayerRect) -> Geometry {
        Geometry {
            local_rect: local_rect,
            bounding_rect: DeviceIntRect::zero(),
        }
    }

    fn update(&mut self,
              transform: &LayerToWorldTransform,
              device_pixel_ratio: f32) {
        let transformed = TransformedRect::new(&self.local_rect,
                                               &transform,
                                               device_pixel_ratio);
        self.bounding_rect = transformed.bounding_rect;
    }
}

/// Depending on the complexity of the clip, we may either
/// know the outer and/or inner rect, or neither or these.
/// In the case of a clip-out, we currently set the mask
/// bounds to be unknown. This is conservative, but ensures
/// correctness. In the future we can make this a lot
/// more clever with some proper region handling.
#[derive(Clone, Debug, PartialEq)]
pub enum MaskBounds {
    /// We know both the outer and inner rect. This is the
    /// fast path for, e.g. a simple rounded rect.
    OuterInner(Geometry, Geometry),
    /// We know the outer rect only.
    Outer(Geometry),
    /// We can't determine the bounds - draw mask over entire rect.
    /// This is currently used for clip-out operations on
    /// box shadows.
    None,
}

#[derive(Clone, Debug)]
pub struct MaskCacheInfo {
    pub clip_range: ClipAddressRange,
    pub effective_clip_count: usize,
    pub image: Option<(ImageMask, GpuStoreAddress)>,
    pub bounds: Option<MaskBounds>,
    pub is_aligned: bool,
}

impl MaskCacheInfo {
    /// Create a new mask cache info. It allocates the GPU store data but leaves
    /// it unitialized for the following `update()` call to deal with.
    pub fn new(clips: &[ClipSource],
               clip_store: &mut VertexDataStore<GpuBlock32>)
               -> Option<MaskCacheInfo> {
        if clips.is_empty() {
            return None;
        }

        let mut image = None;
        let mut clip_count = 0;

        // Work out how much clip data space we need to allocate
        // and if we have an image mask.
        for clip in clips {
            match clip {
                &ClipSource::Complex(..) => {
                    clip_count += 1;
                },
                &ClipSource::Region(ref region, region_mode) => {
                    if let Some(info) = region.image_mask {
                        debug_assert!(image.is_none());     // TODO(gw): Support >1 image mask!
                        image = Some((info, clip_store.alloc(MASK_DATA_GPU_SIZE)));
                    }

                    clip_count += region.complex.length;
                    if region_mode == RegionMode::IncludeRect {
                        clip_count += 1;
                    }
                },
            }
        }

        let clip_range = ClipAddressRange {
            start: if clip_count > 0 {
                clip_store.alloc(CLIP_DATA_GPU_SIZE * clip_count)
            } else {
                GpuStoreAddress(0)
            },
            item_count: clip_count,
        };

        Some(MaskCacheInfo {
            clip_range: clip_range,
            effective_clip_count: clip_range.item_count,
            image: image,
            bounds: None,
            is_aligned: true,
        })
    }

    pub fn update(&mut self,
                  sources: &[ClipSource],
                  transform: &LayerToWorldTransform,
                  clip_store: &mut VertexDataStore<GpuBlock32>,
                  device_pixel_ratio: f32,
                  aux_lists: &AuxiliaryLists) {
        let is_aligned = transform.can_losslessly_transform_and_perspective_project_a_2d_rect();

        // If we haven't cached this info, or if the transform type has changed
        // we need to re-calculate the number of clips.
        if self.bounds.is_none() || self.is_aligned != is_aligned {
            let mut local_rect = Some(LayerRect::new(LayerPoint::new(-MAX_CLIP, -MAX_CLIP),
                                                     LayerSize::new(2.0 * MAX_CLIP, 2.0 * MAX_CLIP)));
            let mut local_inner: Option<LayerRect> = None;
            let mut has_clip_out = false;

            self.effective_clip_count = 0;
            self.is_aligned = is_aligned;

            for source in sources {
                match source {
                    &ClipSource::Complex(rect, radius, mode) => {
                        // Once we encounter a clip-out, we just assume the worst
                        // case clip mask size, for now.
                        if mode == ClipMode::ClipOut {
                            has_clip_out = true;
                        }
                        debug_assert!(self.effective_clip_count < self.clip_range.item_count);
                        let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                        self.effective_clip_count += 1;

                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                        let data = ClipData::uniform(rect, radius, mode);
                        PrimitiveStore::populate_clip_data(slice, data);
                        local_rect = local_rect.and_then(|r| r.intersection(&rect));
                        local_inner = ComplexClipRegion::new(rect, BorderRadius::uniform(radius))
                                                        .get_inner_rect();
                    }
                    &ClipSource::Region(ref region, region_mode) => {
                        local_rect = local_rect.and_then(|r| r.intersection(&region.main));
                        local_inner = match region.image_mask {
                            Some(ref mask) if !mask.repeat => {
                                local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
                                None
                            },
                            Some(_) => None,
                            None => local_rect,
                        };

                        let clips = aux_lists.complex_clip_regions(&region.complex);
                        if !self.is_aligned && region_mode == RegionMode::IncludeRect {
                            // we have an extra clip rect coming from the transformed layer
                            debug_assert!(self.effective_clip_count < self.clip_range.item_count);
                            let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                            self.effective_clip_count += 1;

                            let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                            PrimitiveStore::populate_clip_data(slice, ClipData::uniform(region.main, 0.0, ClipMode::Clip));
                        }

                        debug_assert!(self.effective_clip_count + clips.len() < self.clip_range.item_count);
                        let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                        self.effective_clip_count += clips.len();

                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE * clips.len());
                        for (clip, chunk) in clips.iter().zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
                            let data = ClipData::from_clip_region(clip);
                            PrimitiveStore::populate_clip_data(chunk, data);
                            local_rect = local_rect.and_then(|r| r.intersection(&clip.rect));
                            local_inner = local_inner.and_then(|r| clip.get_inner_rect()
                                                                       .and_then(|ref inner| r.intersection(&inner)));
                        }
                    }
                }
            }

            // Work out the type of mask geometry we have, based on the
            // list of clip sources above.
            if has_clip_out {
                // For clip-out, the mask rect is not known.
                self.bounds = Some(MaskBounds::None);
            } else {
                // TODO(gw): local inner is only valid if there's a single clip (for now).
                // This can be improved in the future, with some proper
                // rectangle region handling.
                if sources.len() > 1 {
                    local_inner = None;
                }

                let local_rect = local_rect.unwrap_or(LayerRect::zero());

                self.bounds = match local_inner {
                    Some(local_inner) => {
                        Some(MaskBounds::OuterInner(Geometry::new(local_rect),
                                                    Geometry::new(local_inner)))
                    }
                    None => {
                        Some(MaskBounds::Outer(Geometry::new(local_rect)))
                    }
                };
            }
        }

        // Update the device space bounding rects of the mask
        // geometry.
        match self.bounds.as_mut().unwrap() {
            &mut MaskBounds::None => {}
            &mut MaskBounds::Outer(ref mut outer) => {
                outer.update(transform, device_pixel_ratio);
            }
            &mut MaskBounds::OuterInner(ref mut outer, ref mut inner) => {
                outer.update(transform, device_pixel_ratio);
                inner.update(transform, device_pixel_ratio);
            }
        }
    }

    /// Check if this `MaskCacheInfo` actually carries any masks. `effective_clip_count`
    /// can change during the `update` call depending on the transformation, so the mask may
    /// appear to be empty.
    pub fn is_masking(&self) -> bool {
        self.image.is_some() || self.effective_clip_count != 0
    }
}
<commit_msg>Auto merge of #1024 - servo:kvark-patch-1, r=glennw<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gpu_store::GpuStoreAddress;
use prim_store::{ClipData, GpuBlock32, PrimitiveStore};
use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
use renderer::VertexDataStore;
use util::{MatrixHelpers, TransformedRect};
use webrender_traits::{AuxiliaryLists, BorderRadius, ClipRegion, ComplexClipRegion, ImageMask};
use webrender_traits::{DeviceIntRect, LayerToWorldTransform};
use webrender_traits::{LayerRect, LayerPoint, LayerSize};

const MAX_CLIP: f32 = 1000000.0;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ClipMode {
    Clip,           // Pixels inside the region are visible.
    ClipOut,        // Pixels outside the region are visible.
}

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RegionMode {
    IncludeRect,
    ExcludeRect,
}

#[derive(Clone, Debug)]
pub enum ClipSource {
    Complex(LayerRect, f32, ClipMode),
    // The RegionMode here specifies whether to consider the rect
    // from the clip region as part of the mask. This is true
    // for clip/scroll nodes, but false for primitives, where
    // the clip rect is handled in local space.
    Region(ClipRegion, RegionMode),
}

impl ClipSource {
    pub fn image_mask(&self) -> Option<ImageMask> {
        match self {
            &ClipSource::Complex(..) => None,
            &ClipSource::Region(ref region, _) => region.image_mask,
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ClipAddressRange {
    pub start: GpuStoreAddress,
    item_count: usize,
}

/// Represents a local rect and a device space
/// bounding rect that can be updated when the
/// transform changes.
#[derive(Clone, Debug, PartialEq)]
pub struct Geometry {
    pub local_rect: LayerRect,
    pub bounding_rect: DeviceIntRect,
}

impl Geometry {
    fn new(local_rect: LayerRect) -> Geometry {
        Geometry {
            local_rect: local_rect,
            bounding_rect: DeviceIntRect::zero(),
        }
    }

    fn update(&mut self,
              transform: &LayerToWorldTransform,
              device_pixel_ratio: f32) {
        let transformed = TransformedRect::new(&self.local_rect,
                                               &transform,
                                               device_pixel_ratio);
        self.bounding_rect = transformed.bounding_rect;
    }
}

/// Depending on the complexity of the clip, we may either
/// know the outer and/or inner rect, or neither or these.
/// In the case of a clip-out, we currently set the mask
/// bounds to be unknown. This is conservative, but ensures
/// correctness. In the future we can make this a lot
/// more clever with some proper region handling.
#[derive(Clone, Debug, PartialEq)]
pub enum MaskBounds {
    /// We know both the outer and inner rect. This is the
    /// fast path for, e.g. a simple rounded rect.
    OuterInner(Geometry, Geometry),
    /// We know the outer rect only.
    Outer(Geometry),
    /// We can't determine the bounds - draw mask over entire rect.
    /// This is currently used for clip-out operations on
    /// box shadows.
    None,
}

#[derive(Clone, Debug)]
pub struct MaskCacheInfo {
    pub clip_range: ClipAddressRange,
    pub effective_clip_count: usize,
    pub image: Option<(ImageMask, GpuStoreAddress)>,
    pub bounds: Option<MaskBounds>,
    pub is_aligned: bool,
}

impl MaskCacheInfo {
    /// Create a new mask cache info. It allocates the GPU store data but leaves
    /// it unitialized for the following `update()` call to deal with.
    pub fn new(clips: &[ClipSource],
               clip_store: &mut VertexDataStore<GpuBlock32>)
               -> Option<MaskCacheInfo> {
        if clips.is_empty() {
            return None;
        }

        let mut image = None;
        let mut clip_count = 0;

        // Work out how much clip data space we need to allocate
        // and if we have an image mask.
        for clip in clips {
            match clip {
                &ClipSource::Complex(..) => {
                    clip_count += 1;
                },
                &ClipSource::Region(ref region, region_mode) => {
                    if let Some(info) = region.image_mask {
                        debug_assert!(image.is_none());     // TODO(gw): Support >1 image mask!
                        image = Some((info, clip_store.alloc(MASK_DATA_GPU_SIZE)));
                    }

                    clip_count += region.complex.length;
                    if region_mode == RegionMode::IncludeRect {
                        clip_count += 1;
                    }
                },
            }
        }

        let clip_range = ClipAddressRange {
            start: if clip_count > 0 {
                clip_store.alloc(CLIP_DATA_GPU_SIZE * clip_count)
            } else {
                GpuStoreAddress(0)
            },
            item_count: clip_count,
        };

        Some(MaskCacheInfo {
            clip_range: clip_range,
            effective_clip_count: clip_range.item_count,
            image: image,
            bounds: None,
            is_aligned: true,
        })
    }

    pub fn update(&mut self,
                  sources: &[ClipSource],
                  transform: &LayerToWorldTransform,
                  clip_store: &mut VertexDataStore<GpuBlock32>,
                  device_pixel_ratio: f32,
                  aux_lists: &AuxiliaryLists) {
        let is_aligned = transform.can_losslessly_transform_and_perspective_project_a_2d_rect();

        // If we haven't cached this info, or if the transform type has changed
        // we need to re-calculate the number of clips.
        if self.bounds.is_none() || self.is_aligned != is_aligned {
            let mut local_rect = Some(LayerRect::new(LayerPoint::new(-MAX_CLIP, -MAX_CLIP),
                                                     LayerSize::new(2.0 * MAX_CLIP, 2.0 * MAX_CLIP)));
            let mut local_inner: Option<LayerRect> = None;
            let mut has_clip_out = false;

            self.effective_clip_count = 0;
            self.is_aligned = is_aligned;

            for source in sources {
                match source {
                    &ClipSource::Complex(rect, radius, mode) => {
                        // Once we encounter a clip-out, we just assume the worst
                        // case clip mask size, for now.
                        if mode == ClipMode::ClipOut {
                            has_clip_out = true;
                        }
                        debug_assert!(self.effective_clip_count < self.clip_range.item_count);
                        let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                        self.effective_clip_count += 1;

                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                        let data = ClipData::uniform(rect, radius, mode);
                        PrimitiveStore::populate_clip_data(slice, data);
                        local_rect = local_rect.and_then(|r| r.intersection(&rect));
                        local_inner = ComplexClipRegion::new(rect, BorderRadius::uniform(radius))
                                                        .get_inner_rect();
                    }
                    &ClipSource::Region(ref region, region_mode) => {
                        local_rect = local_rect.and_then(|r| r.intersection(&region.main));
                        local_inner = match region.image_mask {
                            Some(ref mask) if !mask.repeat => {
                                local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
                                None
                            },
                            Some(_) => None,
                            None => local_rect,
                        };

                        let clips = aux_lists.complex_clip_regions(&region.complex);
                        if !self.is_aligned && region_mode == RegionMode::IncludeRect {
                            // we have an extra clip rect coming from the transformed layer
                            debug_assert!(self.effective_clip_count < self.clip_range.item_count);
                            let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                            self.effective_clip_count += 1;

                            let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                            PrimitiveStore::populate_clip_data(slice, ClipData::uniform(region.main, 0.0, ClipMode::Clip));
                        }

                        debug_assert!(self.effective_clip_count + clips.len() <= self.clip_range.item_count);
                        let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                        self.effective_clip_count += clips.len();

                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE * clips.len());
                        for (clip, chunk) in clips.iter().zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
                            let data = ClipData::from_clip_region(clip);
                            PrimitiveStore::populate_clip_data(chunk, data);
                            local_rect = local_rect.and_then(|r| r.intersection(&clip.rect));
                            local_inner = local_inner.and_then(|r| clip.get_inner_rect()
                                                                       .and_then(|ref inner| r.intersection(&inner)));
                        }
                    }
                }
            }

            // Work out the type of mask geometry we have, based on the
            // list of clip sources above.
            if has_clip_out {
                // For clip-out, the mask rect is not known.
                self.bounds = Some(MaskBounds::None);
            } else {
                // TODO(gw): local inner is only valid if there's a single clip (for now).
                // This can be improved in the future, with some proper
                // rectangle region handling.
                if sources.len() > 1 {
                    local_inner = None;
                }

                let local_rect = local_rect.unwrap_or(LayerRect::zero());

                self.bounds = match local_inner {
                    Some(local_inner) => {
                        Some(MaskBounds::OuterInner(Geometry::new(local_rect),
                                                    Geometry::new(local_inner)))
                    }
                    None => {
                        Some(MaskBounds::Outer(Geometry::new(local_rect)))
                    }
                };
            }
        }

        // Update the device space bounding rects of the mask
        // geometry.
        match self.bounds.as_mut().unwrap() {
            &mut MaskBounds::None => {}
            &mut MaskBounds::Outer(ref mut outer) => {
                outer.update(transform, device_pixel_ratio);
            }
            &mut MaskBounds::OuterInner(ref mut outer, ref mut inner) => {
                outer.update(transform, device_pixel_ratio);
                inner.update(transform, device_pixel_ratio);
            }
        }
    }

    /// Check if this `MaskCacheInfo` actually carries any masks. `effective_clip_count`
    /// can change during the `update` call depending on the transformation, so the mask may
    /// appear to be empty.
    pub fn is_masking(&self) -> bool {
        self.image.is_some() || self.effective_clip_count != 0
    }
}
<|endoftext|>