<commit_before>// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

//! Receipt

use BlockNumber;
use log_entry::{LogBloom, LogEntry, LocalizedLogEntry};
use rlp::*;
use util::{H256, U256, Address};
use util::HeapSizeOf;

// TODO: Add evm errors?
#[derive(Debug, PartialEq, Clone, Copy, Eq)]
pub enum ReceiptError {
    NoTransactionPermission,
    NoContractPermission,
    NotEnoughBaseGas,
    BlockGasLimitReached,
    AccountGasLimitReached,
}

impl ReceiptError {
    /// Returns human-readable description
    pub fn description(&self) -> String {
        let desc = match *self {
            ReceiptError::NoTransactionPermission => "No transaction permission.",
            ReceiptError::NoContractPermission => "No contract permission.",
            ReceiptError::NotEnoughBaseGas => "Not enough base gas.",
            ReceiptError::BlockGasLimitReached => "Block gas limit reached.",
            ReceiptError::AccountGasLimitReached => "Account gas limit reached.",
        };
        desc.to_string()
    }
}

impl Decodable for ReceiptError {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        match rlp.as_val::<u8>()? {
            0 => Ok(ReceiptError::NoTransactionPermission),
            1 => Ok(ReceiptError::NoContractPermission),
            2 => Ok(ReceiptError::NotEnoughBaseGas),
            3 => Ok(ReceiptError::BlockGasLimitReached),
            4 => Ok(ReceiptError::AccountGasLimitReached),
            _ => Err(DecoderError::Custom("Unknown Receipt error.")),
        }
    }
}

impl Encodable for ReceiptError {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&(*self as u8));
    }
}

/// Information describing execution of a transaction.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Receipt {
    /// The state root after executing the transaction. Optional since EIP98
    pub state_root: Option<H256>,
    /// The total gas used in the block following execution of the transaction.
    pub gas_used: U256,
    /// The OR-wide combination of all logs' blooms for this transaction.
    pub log_bloom: LogBloom,
    /// The logs stemming from this transaction.
    pub logs: Vec<LogEntry>,
    /// Transaction transact error
    pub error: Option<ReceiptError>,
}

impl Receipt {
    /// Create a new receipt.
    pub fn new(state_root: Option<H256>, gas_used: U256, logs: Vec<LogEntry>, error: Option<ReceiptError>) -> Receipt {
        Receipt {
            state_root: state_root,
            gas_used: gas_used,
            log_bloom: logs.iter().fold(LogBloom::default(), |mut b, l| {
                b = &b | &l.bloom();
                b
            }), //TODO: use |= operator
            logs: logs,
            error: error,
        }
    }
}

impl Encodable for Receipt {
    fn rlp_append(&self, s: &mut RlpStream) {
        if let Some(ref root) = self.state_root {
            s.begin_list(4);
            s.append(root);
        } else {
            s.begin_list(3);
        }
        s.append(&self.gas_used);
        s.append(&self.log_bloom);
        s.append_list(&self.logs);
        s.append(&self.error);
    }
}

impl Decodable for Receipt {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        if rlp.item_count()? == 4 {
            Ok(Receipt {
                   state_root: None,
                   gas_used: rlp.val_at(0)?,
                   log_bloom: rlp.val_at(1)?,
                   logs: rlp.list_at(2)?,
                   error: rlp.val_at(3)?,
               })
        } else {
            Ok(Receipt {
                   state_root: Some(rlp.val_at(0)?),
                   gas_used: rlp.val_at(1)?,
                   log_bloom: rlp.val_at(2)?,
                   logs: rlp.list_at(3)?,
                   error: rlp.val_at(4)?,
               })
        }
    }
}

impl HeapSizeOf for Receipt {
    fn heap_size_of_children(&self) -> usize {
        self.logs.heap_size_of_children()
    }
}

/// Receipt with additional info.
#[derive(Debug, Clone, PartialEq)]
pub struct RichReceipt {
    /// Transaction hash.
    pub transaction_hash: H256,
    /// Transaction index.
    pub transaction_index: usize,
    /// The total gas used in the block following execution of the transaction.
    pub cumulative_gas_used: U256,
    /// The gas used in the execution of the transaction. Note the difference of meaning to `Receipt::gas_used`.
    pub gas_used: U256,
    /// Contract address.
    pub contract_address: Option<Address>,
    /// Logs
    pub logs: Vec<LogEntry>,
    /// Logs bloom
    pub log_bloom: LogBloom,
    /// State root
    pub state_root: Option<H256>,
    /// Receipt error
    pub error: Option<ReceiptError>,
}

/// Receipt with additional info.
#[derive(Debug, Clone, PartialEq)]
pub struct LocalizedReceipt {
    /// Transaction hash.
    pub transaction_hash: H256,
    /// Transaction index.
    pub transaction_index: usize,
    /// Block hash.
    pub block_hash: H256,
    /// Block number.
    pub block_number: BlockNumber,
    /// The total gas used in the block following execution of the transaction.
    pub cumulative_gas_used: U256,
    /// The gas used in the execution of the transaction. Note the difference of meaning to `Receipt::gas_used`.
    pub gas_used: U256,
    /// Contract address.
    pub contract_address: Option<Address>,
    /// Logs
    pub logs: Vec<LocalizedLogEntry>,
    /// Logs bloom
    pub log_bloom: LogBloom,
    /// State root
    pub state_root: Option<H256>,
    /// Receipt error
    pub error: Option<ReceiptError>,
}

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

    #[test]
    fn test_no_state_root() {
        let r = Receipt::new(
            None,
            0x40cae.into(),
            vec![
                LogEntry {
                    address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
                    topics: vec![],
                    data: vec![0u8; 32],
                },
            ],
            None,
        );
        let encoded = ::rlp::encode(&r);
        println!("encode ok");
        let decoded: Receipt = ::rlp::decode(&encoded);
        println!("decoded: {:?}", decoded);
        assert_eq!(decoded, r);
    }

    #[test]
    fn test_basic() {
        let r = Receipt::new(
            Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()),
            0x40cae.into(),
            vec![
                LogEntry {
                    address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
                    topics: vec![],
                    data: vec![0u8; 32],
                },
            ],
            None,
        );
        let encoded = ::rlp::encode(&r);
        let decoded: Receipt = ::rlp::decode(&encoded);
        println!("decoded: {:?}", decoded);
        assert_eq!(decoded, r);
    }

    #[test]
    fn test_with_error() {
        let r = Receipt::new(
            Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()),
            0x40cae.into(),
            vec![
                LogEntry {
                    address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
                    topics: vec![],
                    data: vec![0u8; 32],
                },
            ],
            Some(ReceiptError::NoTransactionPermission),
        );
        let encoded = ::rlp::encode(&r);
        let decoded: Receipt = ::rlp::decode(&encoded);
        println!("decoded: {:?}", decoded);
        assert_eq!(decoded, r);
    }
}
<commit_msg>Fixed receipt rlp<commit_after>// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

//! Receipt

use BlockNumber;
use log_entry::{LogBloom, LogEntry, LocalizedLogEntry};
use rlp::*;
use util::{H256, U256, Address};
use util::HeapSizeOf;

// TODO: Add evm errors?
#[derive(Debug, PartialEq, Clone, Copy, Eq)]
pub enum ReceiptError {
    NoTransactionPermission,
    NoContractPermission,
    NotEnoughBaseGas,
    BlockGasLimitReached,
    AccountGasLimitReached,
}

impl ReceiptError {
    /// Returns human-readable description
    pub fn description(&self) -> String {
        let desc = match *self {
            ReceiptError::NoTransactionPermission => "No transaction permission.",
            ReceiptError::NoContractPermission => "No contract permission.",
            ReceiptError::NotEnoughBaseGas => "Not enough base gas.",
            ReceiptError::BlockGasLimitReached => "Block gas limit reached.",
            ReceiptError::AccountGasLimitReached => "Account gas limit reached.",
        };
        desc.to_string()
    }
}

impl Decodable for ReceiptError {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        match rlp.as_val::<u8>()? {
            0 => Ok(ReceiptError::NoTransactionPermission),
            1 => Ok(ReceiptError::NoContractPermission),
            2 => Ok(ReceiptError::NotEnoughBaseGas),
            3 => Ok(ReceiptError::BlockGasLimitReached),
            4 => Ok(ReceiptError::AccountGasLimitReached),
            _ => Err(DecoderError::Custom("Unknown Receipt error.")),
        }
    }
}

impl Encodable for ReceiptError {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&(*self as u8));
    }
}

/// Information describing execution of a transaction.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Receipt {
    /// The state root after executing the transaction. Optional since EIP98
    pub state_root: Option<H256>,
    /// The total gas used in the block following execution of the transaction.
    pub gas_used: U256,
    /// The OR-wide combination of all logs' blooms for this transaction.
    pub log_bloom: LogBloom,
    /// The logs stemming from this transaction.
    pub logs: Vec<LogEntry>,
    /// Transaction transact error
    pub error: Option<ReceiptError>,
}

impl Receipt {
    /// Create a new receipt.
    pub fn new(state_root: Option<H256>, gas_used: U256, logs: Vec<LogEntry>, error: Option<ReceiptError>) -> Receipt {
        Receipt {
            state_root: state_root,
            gas_used: gas_used,
            log_bloom: logs.iter().fold(LogBloom::default(), |mut b, l| {
                b = &b | &l.bloom();
                b
            }), //TODO: use |= operator
            logs: logs,
            error: error,
        }
    }
}

impl Encodable for Receipt {
    fn rlp_append(&self, s: &mut RlpStream) {
        if let Some(ref root) = self.state_root {
            s.begin_list(5);
            s.append(root);
        } else {
            s.begin_list(4);
        }
        s.append(&self.gas_used);
        s.append(&self.log_bloom);
        s.append_list(&self.logs);
        s.append(&self.error);
    }
}

impl Decodable for Receipt {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        if rlp.item_count()? == 4 {
            Ok(Receipt {
                   state_root: None,
                   gas_used: rlp.val_at(0)?,
                   log_bloom: rlp.val_at(1)?,
                   logs: rlp.list_at(2)?,
                   error: rlp.val_at(3)?,
               })
        } else {
            Ok(Receipt {
                   state_root: Some(rlp.val_at(0)?),
                   gas_used: rlp.val_at(1)?,
                   log_bloom: rlp.val_at(2)?,
                   logs: rlp.list_at(3)?,
                   error: rlp.val_at(4)?,
               })
        }
    }
}

impl HeapSizeOf for Receipt {
    fn heap_size_of_children(&self) -> usize {
        self.logs.heap_size_of_children()
    }
}

/// Receipt with additional info.
#[derive(Debug, Clone, PartialEq)]
pub struct RichReceipt {
    /// Transaction hash.
    pub transaction_hash: H256,
    /// Transaction index.
    pub transaction_index: usize,
    /// The total gas used in the block following execution of the transaction.
    pub cumulative_gas_used: U256,
    /// The gas used in the execution of the transaction. Note the difference of meaning to `Receipt::gas_used`.
    pub gas_used: U256,
    /// Contract address.
    pub contract_address: Option<Address>,
    /// Logs
    pub logs: Vec<LogEntry>,
    /// Logs bloom
    pub log_bloom: LogBloom,
    /// State root
    pub state_root: Option<H256>,
    /// Receipt error
    pub error: Option<ReceiptError>,
}

/// Receipt with additional info.
#[derive(Debug, Clone, PartialEq)]
pub struct LocalizedReceipt {
    /// Transaction hash.
    pub transaction_hash: H256,
    /// Transaction index.
    pub transaction_index: usize,
    /// Block hash.
    pub block_hash: H256,
    /// Block number.
    pub block_number: BlockNumber,
    /// The total gas used in the block following execution of the transaction.
    pub cumulative_gas_used: U256,
    /// The gas used in the execution of the transaction. Note the difference of meaning to `Receipt::gas_used`.
    pub gas_used: U256,
    /// Contract address.
    pub contract_address: Option<Address>,
    /// Logs
    pub logs: Vec<LocalizedLogEntry>,
    /// Logs bloom
    pub log_bloom: LogBloom,
    /// State root
    pub state_root: Option<H256>,
    /// Receipt error
    pub error: Option<ReceiptError>,
}

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

    #[test]
    fn test_no_state_root() {
        let r = Receipt::new(
            None,
            0x40cae.into(),
            vec![
                LogEntry {
                    address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
                    topics: vec![],
                    data: vec![0u8; 32],
                },
            ],
            None,
        );
        let encoded = ::rlp::encode(&r);
        println!("encode ok");
        let decoded: Receipt = ::rlp::decode(&encoded);
        println!("decoded: {:?}", decoded);
        assert_eq!(decoded, r);
    }

    #[test]
    fn test_basic() {
        let r = Receipt::new(
            Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()),
            0x40cae.into(),
            vec![
                LogEntry {
                    address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
                    topics: vec![],
                    data: vec![0u8; 32],
                },
            ],
            None,
        );
        let encoded = ::rlp::encode(&r);
        let decoded: Receipt = ::rlp::decode(&encoded);
        println!("decoded: {:?}", decoded);
        assert_eq!(decoded, r);
    }

    #[test]
    fn test_with_error() {
        let r = Receipt::new(
            Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()),
            0x40cae.into(),
            vec![
                LogEntry {
                    address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
                    topics: vec![],
                    data: vec![0u8; 32],
                },
            ],
            Some(ReceiptError::NoTransactionPermission),
        );
        let encoded = ::rlp::encode(&r);
        let decoded: Receipt = ::rlp::decode(&encoded);
        println!("decoded: {:?}", decoded);
        assert_eq!(decoded, r);
    }
}
<|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 std::env;
use std::fs::File;
use std::io::Write;
use std::process::{Command, Stdio};
use std::path::Path;

fn main() {
    let python = if Command::new("python2.7").arg("--version").status().unwrap().success() {
        "python2.7"
    } else {
        "python"
    };
    let style = Path::new(file!()).parent().unwrap();
    let mako = style.join("Mako-0.9.1.zip");
    let template = style.join("properties.mako.rs");
    let result = Command::new(python)
        .env("PYTHONPATH", &mako)
        .env("TEMPLATE", &template)
        .arg("-c")
        .arg("from os import environ; from mako.template import Template; \
              from mako import exceptions; \n\
              try:\n    print(Template(filename=environ['TEMPLATE']).render());\n\
              except:\n    print exceptions.html_error_template().render()")
        .stderr(Stdio::inherit())
        .output()
        .unwrap();
    assert!(result.status.success());
    let out = env::var("OUT_DIR").unwrap();
    File::create(&Path::new(&out).join("properties.rs")).unwrap().write_all(&result.stdout).unwrap();
}
<commit_msg>Show Mako template errors on the console<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 std::env;
use std::fs::File;
use std::io::Write;
use std::process::{Command, Stdio, exit};
use std::path::Path;

fn main() {
    let python = if Command::new("python2.7").arg("--version").output().unwrap().status.success() {
        "python2.7"
    } else {
        "python"
    };
    let style = Path::new(file!()).parent().unwrap();
    let mako = style.join("Mako-0.9.1.zip");
    let template = style.join("properties.mako.rs");
    let result = Command::new(python)
        .env("PYTHONPATH", &mako)
        .env("TEMPLATE", &template)
        .arg("-c")
        .arg(r#"
import os
import sys
from mako.template import Template
from mako import exceptions
try:
    print(Template(filename=os.environ['TEMPLATE']).render())
except:
    sys.stderr.write(exceptions.text_error_template().render().encode('utf8'))
    sys.exit(1)
"#)
        .stderr(Stdio::inherit())
        .output()
        .unwrap();
    if !result.status.success() {
        exit(1)
    }
    let out = env::var("OUT_DIR").unwrap();
    File::create(&Path::new(&out).join("properties.rs")).unwrap().write_all(&result.stdout).unwrap();
}
<|endoftext|>


<commit_before>use std::env;
use std::io::Write;
use std::io::{BufWriter, Result};
use std::process::{Child, Command, Stdio};
/// A writer that writes to a shell_process' stdin
///
/// We use a shell process (not directly calling a sub-process) so we can forward the name of the
/// corresponding output file (xaa, xab, xac… ). This is the way it was implemented in GNU split.
struct FilterWriter {
    /// Running shell process
    shell_process: Child,
}

impl Write for FilterWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.shell_process
            .stdin
            .as_mut()
            .expect("failed to get shell stdin")
            .write(buf)
    }
    fn flush(&mut self) -> Result<()> {
        self.shell_process
            .stdin
            .as_mut()
            .expect("failed to get shell stdin")
            .flush()
    }
}

/// Have an environment variable set at a value during this lifetime
struct WithEnvVarSet {
    /// Env var key
    _previous_var_key: String,
    /// Previous value set to this key
    _previous_var_value: std::result::Result<String, env::VarError>,
}
impl WithEnvVarSet {
    /// Save previous value assigned to key, set key=value
    fn new(key: &str, value: &str) -> WithEnvVarSet {
        let previous_env_value = env::var(key);
        env::set_var(key, value);
        WithEnvVarSet {
            _previous_var_key: String::from(key),
            _previous_var_value: previous_env_value,
        }
    }
}

impl Drop for WithEnvVarSet {
    /// Restore previous value now that this is being dropped by context
    fn drop(&mut self) {
        if let Ok(ref prev_value) = self._previous_var_value {
            env::set_var(&self._previous_var_key, &prev_value);
        } else {
            env::remove_var(&self._previous_var_key)
        }
    }
}
impl FilterWriter {
    /// Create a new filter running a command with $FILE pointing at the output name
    ///
    /// #Arguments
    ///
    /// * `command` - The shell command to execute
    /// * `filepath` - Path of the output file (forwarded to command as $FILE)
    fn new(command: &str, filepath: &str) -> FilterWriter {
        // set $FILE, save previous value (if there was one)
        let _with_env_var_set = WithEnvVarSet::new("FILE", &filepath);

        let shell_process =
            Command::new(env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_owned()))
                .arg("-c")
                .arg(command)
                .stdin(Stdio::piped())
                .spawn()
                .expect("Couldn't spawn filter command");

        FilterWriter { shell_process }
    }
}

impl Drop for FilterWriter {
    /// flush stdin, close it and wait on `shell_process` before dropping self
    fn drop(&mut self) {
        {
            // close stdin by dropping it
            let _stdin = self.shell_process.stdin.as_mut();
        }
        let exit_status = self
            .shell_process
            .wait()
            .expect("Couldn't wait for child process");
        if let Some(return_code) = exit_status.code() {
            if return_code != 0 {
                crash!(1, "Shell process returned {}", return_code);
            }
        } else {
            crash!(1, "Shell process terminated by signal")
        }
    }
}

/// Instantiate either a file writer or a "write to shell process's stdin" writer
pub fn instantiate_current_writer(
    filter: &Option<String>,
    filename: &str,
) -> BufWriter<Box<dyn Write>> {
    match filter {
        None => BufWriter::new(Box::new(
            // write to the next file
            std::fs::OpenOptions::new()
                .write(true)
                .create(true)
                .open(std::path::Path::new(&filename))
                .unwrap(),
        ) as Box<dyn Write>),
        Some(ref filter_command) => BufWriter::new(Box::new(
            // spawn a shell command and write to it
            FilterWriter::new(&filter_command, &filename),
        ) as Box<dyn Write>),
    }
}
<commit_msg>refactor/split ~ fix `cargo clippy` complaint (clippy::needless_borrow)<commit_after>use std::env;
use std::io::Write;
use std::io::{BufWriter, Result};
use std::process::{Child, Command, Stdio};
/// A writer that writes to a shell_process' stdin
///
/// We use a shell process (not directly calling a sub-process) so we can forward the name of the
/// corresponding output file (xaa, xab, xac… ). This is the way it was implemented in GNU split.
struct FilterWriter {
    /// Running shell process
    shell_process: Child,
}

impl Write for FilterWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.shell_process
            .stdin
            .as_mut()
            .expect("failed to get shell stdin")
            .write(buf)
    }
    fn flush(&mut self) -> Result<()> {
        self.shell_process
            .stdin
            .as_mut()
            .expect("failed to get shell stdin")
            .flush()
    }
}

/// Have an environment variable set at a value during this lifetime
struct WithEnvVarSet {
    /// Env var key
    _previous_var_key: String,
    /// Previous value set to this key
    _previous_var_value: std::result::Result<String, env::VarError>,
}
impl WithEnvVarSet {
    /// Save previous value assigned to key, set key=value
    fn new(key: &str, value: &str) -> WithEnvVarSet {
        let previous_env_value = env::var(key);
        env::set_var(key, value);
        WithEnvVarSet {
            _previous_var_key: String::from(key),
            _previous_var_value: previous_env_value,
        }
    }
}

impl Drop for WithEnvVarSet {
    /// Restore previous value now that this is being dropped by context
    fn drop(&mut self) {
        if let Ok(ref prev_value) = self._previous_var_value {
            env::set_var(&self._previous_var_key, &prev_value);
        } else {
            env::remove_var(&self._previous_var_key)
        }
    }
}
impl FilterWriter {
    /// Create a new filter running a command with $FILE pointing at the output name
    ///
    /// #Arguments
    ///
    /// * `command` - The shell command to execute
    /// * `filepath` - Path of the output file (forwarded to command as $FILE)
    fn new(command: &str, filepath: &str) -> FilterWriter {
        // set $FILE, save previous value (if there was one)
        let _with_env_var_set = WithEnvVarSet::new("FILE", filepath);

        let shell_process =
            Command::new(env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_owned()))
                .arg("-c")
                .arg(command)
                .stdin(Stdio::piped())
                .spawn()
                .expect("Couldn't spawn filter command");

        FilterWriter { shell_process }
    }
}

impl Drop for FilterWriter {
    /// flush stdin, close it and wait on `shell_process` before dropping self
    fn drop(&mut self) {
        {
            // close stdin by dropping it
            let _stdin = self.shell_process.stdin.as_mut();
        }
        let exit_status = self
            .shell_process
            .wait()
            .expect("Couldn't wait for child process");
        if let Some(return_code) = exit_status.code() {
            if return_code != 0 {
                crash!(1, "Shell process returned {}", return_code);
            }
        } else {
            crash!(1, "Shell process terminated by signal")
        }
    }
}

/// Instantiate either a file writer or a "write to shell process's stdin" writer
pub fn instantiate_current_writer(
    filter: &Option<String>,
    filename: &str,
) -> BufWriter<Box<dyn Write>> {
    match filter {
        None => BufWriter::new(Box::new(
            // write to the next file
            std::fs::OpenOptions::new()
                .write(true)
                .create(true)
                .open(std::path::Path::new(&filename))
                .unwrap(),
        ) as Box<dyn Write>),
        Some(ref filter_command) => BufWriter::new(Box::new(
            // spawn a shell command and write to it
            FilterWriter::new(filter_command, filename),
        ) as Box<dyn Write>),
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, All Contributors (see CONTRIBUTORS file)
//
// 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/.
//!
//! # Env Heap
//!
//! This module implements algorithms for managing Env heap
//!

use alloc::raw_vec::RawVec;
use std::cmp;
use std::slice;

/// EnvHeap's main goal is to ensure that raw chunks
/// of memory are never reallocated, thus invalidating
/// references.
///
/// EnvHeap accomplishes that by adding new chunks instead
/// of resizing existing ones.
pub struct EnvHeap {
    chunks: Vec<(usize, RawVec<u8>)>,
}

impl EnvHeap {
    /// Creates new EnvHeap with a certain chunk size, which
    /// can't be changed later
    pub fn new(chunk_size: usize) -> Self {
        EnvHeap { chunks: vec![(0, RawVec::with_capacity(chunk_size))] }
    }

    /// Allocates a new mutable slice
    pub fn alloc(&mut self, size: usize) -> &mut [u8] {
        let (mut ptr, chunk) = self.chunks.pop().unwrap();
        let cap = chunk.cap();
        if ptr + size > cap {
            self.chunks.push((ptr, chunk));
            self.chunks.push((0, RawVec::with_capacity(cmp::max(cap, size))));
            self.alloc(size)
        } else {
            let slice_ptr = unsafe { chunk.ptr().offset(ptr as isize) };
            ptr += size;
            self.chunks.push((ptr, chunk));
            unsafe { slice::from_raw_parts_mut(slice_ptr, size) }
        }
    }
}

#[cfg(test)]
#[allow(unused_variables, unused_must_use, unused_mut)]
mod tests {
    use script::envheap::EnvHeap;

    #[test]
    fn alloc() {
        let mut heap = EnvHeap::new(32_768);
        let sz = 20_000;
        for i in 1..100 {
            heap.alloc(sz);
        }
    }
}
<commit_msg>Problem: EnvHeap allocator is wasteful.<commit_after>// Copyright (c) 2017, All Contributors (see CONTRIBUTORS file)
//
// 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/.
//!
//! # Env Heap
//!
//! This module implements algorithms for managing Env heap
//!

use alloc::raw_vec::RawVec;
use std::cmp;
use std::slice;

/// EnvHeap's main goal is to ensure that raw chunks
/// of memory are never reallocated, thus invalidating
/// references.
///
/// EnvHeap accomplishes that by adding new chunks instead
/// of resizing existing ones.
pub struct EnvHeap {
    chunks: Vec<(usize, RawVec<u8>)>,
}

impl EnvHeap {
    /// Creates new EnvHeap with a certain chunk size, which
    /// can't be changed later
    pub fn new(chunk_size: usize) -> Self {
        EnvHeap { chunks: vec![(0, RawVec::with_capacity(chunk_size))] }
    }

    /// Allocates a new mutable slice
    pub fn alloc(&mut self, size: usize) -> &mut [u8] {
        let nchunks = self.chunks.len();
        //Look for chunks with enough free space.
        for i in 0..nchunks {
            let cap = self.chunks[i].1.cap();
            let ptr = self.chunks[i].0;
            if ptr + size > cap {
                if i == (nchunks - 1) {
                    self.chunks.push((0, RawVec::with_capacity(cmp::max(cap, size))));
                    return self.alloc(size)
                } else {
                    continue;
                }
            } else {
                let (mut ptr, chunk) = self.chunks.pop().unwrap();
                let slice_ptr = unsafe { chunk.ptr().offset(ptr as isize) };
                ptr += size;
                self.chunks.push((ptr, chunk));
                return unsafe { slice::from_raw_parts_mut(slice_ptr, size) }
            }
        }
        unreachable!();
    }
}

#[cfg(test)]
#[allow(unused_variables, unused_must_use, unused_mut)]
mod tests {
    use script::envheap::EnvHeap;

    #[test]
    fn alloc() {
        let mut heap = EnvHeap::new(32_768);
        let sz_0 = 20_000;
        let sz_1 = 10_000;
        for i in 1..100 {
            if (i % 2) == 0 {
                heap.alloc(sz_1);
            } else {
                heap.alloc(sz_0);
            }
        }
        assert_eq!(50, heap.chunks.len());
    }
}
<|endoftext|>


<commit_before>use crate::check::{FnCtxt, LocalTy, UserType};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::PatKind;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::Ty;
use rustc_span::Span;
use rustc_trait_selection::traits;
use std::mem;

pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
    fcx: &'a FnCtxt<'a, 'tcx>,
    parent_id: hir::HirId,
    // params are special cases of pats, but we want to handle them as
    // *distinct* cases. so track when we are hitting a pat *within* an fn
    // param.
    within_fn_param: bool,
}

impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
    pub(super) fn new(
        fcx: &'a FnCtxt<'a, 'tcx>,
        parent_id: hir::HirId,
        within_fn_param: bool,
    ) -> Self {
        Self { fcx, parent_id, within_fn_param }
    }

    fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
        match ty_opt {
            None => {
                // Infer the variable's type.
                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin {
                    kind: TypeVariableOriginKind::TypeInference,
                    span,
                });
                self.fcx
                    .locals
                    .borrow_mut()
                    .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
                var_ty
            }
            Some(typ) => {
                // Take type that the user specified.
                self.fcx.locals.borrow_mut().insert(nid, typ);
                typ.revealed_ty
            }
        }
    }
}

impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
    type Map = intravisit::ErasedMap<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }

    // Add explicitly-declared locals.
    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
        let local_ty = match local.ty {
            Some(ref ty) => {
                let o_ty = self.fcx.to_ty(&ty);

                let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
                    self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span)
                } else {
                    o_ty
                };

                let c_ty = self
                    .fcx
                    .inh
                    .infcx
                    .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty));
                debug!(
                    "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
                    ty.hir_id, o_ty, revealed_ty, c_ty
                );
                self.fcx
                    .typeck_results
                    .borrow_mut()
                    .user_provided_types_mut()
                    .insert(ty.hir_id, c_ty);

                Some(LocalTy { decl_ty: o_ty, revealed_ty })
            }
            None => None,
        };
        self.assign(local.span, local.hir_id, local_ty);

        debug!(
            "local variable {:?} is assigned type {}",
            local.pat,
            self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
        );
        intravisit::walk_local(self, local);
    }

    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
        let old_within_fn_param = mem::replace(&mut self.within_fn_param, true);
        intravisit::walk_param(self, param);
        self.within_fn_param = old_within_fn_param;
    }

    // Add pattern bindings.
    fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
        if let PatKind::Binding(_, _, ident, _) = p.kind {
            let var_ty = self.assign(p.span, p.hir_id, None);

            if self.within_fn_param {
                if !self.fcx.tcx.features().unsized_fn_params {
                    self.fcx.require_type_is_sized(
                        var_ty,
                        p.span,
                        traits::SizedArgumentType(Some(p.span)),
                    );
                }
            } else {
                if !self.fcx.tcx.features().unsized_locals {
                    self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
                }
            }

            debug!(
                "pattern binding {} is assigned to {} with type {:?}",
                ident,
                self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
                var_ty
            );
        }
        let old_within_fn_param = mem::replace(&mut self.within_fn_param, false);
        intravisit::walk_pat(self, p);
        self.within_fn_param = old_within_fn_param;
    }

    // Don't descend into the bodies of nested closures.
    fn visit_fn(
        &mut self,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx hir::FnDecl<'tcx>,
        _: hir::BodyId,
        _: Span,
        _: hir::HirId,
    ) {
    }
}
<commit_msg>Rename within_fn_param to outermost_fn_param_pat<commit_after>use crate::check::{FnCtxt, LocalTy, UserType};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::PatKind;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::Ty;
use rustc_span::Span;
use rustc_trait_selection::traits;
use std::mem;

pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
    fcx: &'a FnCtxt<'a, 'tcx>,
    parent_id: hir::HirId,
    // params are special cases of pats, but we want to handle them as
    // *distinct* cases. so track when we are hitting a pat *within* an fn
    // param.
    outermost_fn_param_pat: bool,
}

impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
    pub(super) fn new(
        fcx: &'a FnCtxt<'a, 'tcx>,
        parent_id: hir::HirId,
        outermost_fn_param_pat: bool,
    ) -> Self {
        Self { fcx, parent_id, outermost_fn_param_pat }
    }

    fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
        match ty_opt {
            None => {
                // Infer the variable's type.
                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin {
                    kind: TypeVariableOriginKind::TypeInference,
                    span,
                });
                self.fcx
                    .locals
                    .borrow_mut()
                    .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
                var_ty
            }
            Some(typ) => {
                // Take type that the user specified.
                self.fcx.locals.borrow_mut().insert(nid, typ);
                typ.revealed_ty
            }
        }
    }
}

impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
    type Map = intravisit::ErasedMap<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }

    // Add explicitly-declared locals.
    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
        let local_ty = match local.ty {
            Some(ref ty) => {
                let o_ty = self.fcx.to_ty(&ty);

                let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
                    self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span)
                } else {
                    o_ty
                };

                let c_ty = self
                    .fcx
                    .inh
                    .infcx
                    .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty));
                debug!(
                    "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
                    ty.hir_id, o_ty, revealed_ty, c_ty
                );
                self.fcx
                    .typeck_results
                    .borrow_mut()
                    .user_provided_types_mut()
                    .insert(ty.hir_id, c_ty);

                Some(LocalTy { decl_ty: o_ty, revealed_ty })
            }
            None => None,
        };
        self.assign(local.span, local.hir_id, local_ty);

        debug!(
            "local variable {:?} is assigned type {}",
            local.pat,
            self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
        );
        intravisit::walk_local(self, local);
    }

    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
        let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, true);
        intravisit::walk_param(self, param);
        self.outermost_fn_param_pat = old_outermost_fn_param_pat;
    }

    // Add pattern bindings.
    fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
        if let PatKind::Binding(_, _, ident, _) = p.kind {
            let var_ty = self.assign(p.span, p.hir_id, None);

            if self.outermost_fn_param_pat {
                if !self.fcx.tcx.features().unsized_fn_params {
                    self.fcx.require_type_is_sized(
                        var_ty,
                        p.span,
                        traits::SizedArgumentType(Some(p.span)),
                    );
                }
            } else {
                if !self.fcx.tcx.features().unsized_locals {
                    self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
                }
            }

            debug!(
                "pattern binding {} is assigned to {} with type {:?}",
                ident,
                self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
                var_ty
            );
        }
        let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, false);
        intravisit::walk_pat(self, p);
        self.outermost_fn_param_pat = old_outermost_fn_param_pat;
    }

    // Don't descend into the bodies of nested closures.
    fn visit_fn(
        &mut self,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx hir::FnDecl<'tcx>,
        _: hir::BodyId,
        _: Span,
        _: hir::HirId,
    ) {
    }
}
<|endoftext|>


<commit_before>use rustc::hir::intravisit as visit;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::middle::expr_use_visitor::*;
use rustc::middle::mem_categorization::{cmt_, Categorization};
use rustc::ty::layout::LayoutOf;
use rustc::ty::{self, Ty};
use rustc::util::nodemap::HirIdSet;
use rustc::{declare_tool_lint, impl_lint_pass};
use syntax::source_map::Span;

use crate::utils::span_lint;

#[derive(Copy, Clone)]
pub struct BoxedLocal {
    pub too_large_for_stack: u64,
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `Box<T>` where an unboxed `T` would
    /// work fine.
    ///
    /// **Why is this bad?** This is an unnecessary allocation, and bad for
    /// performance. It is only necessary to allocate if you wish to move the box
    /// into something.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn main() {
    ///     let x = Box::new(1);
    ///     foo(*x);
    ///     println!("{}", *x);
    /// }
    /// ```
    pub BOXED_LOCAL,
    perf,
    "using `Box<T>` where unnecessary"
}

fn is_non_trait_box(ty: Ty<'_>) -> bool {
    ty.is_box() && !ty.boxed_ty().is_trait()
}

struct EscapeDelegate<'a, 'tcx> {
    cx: &'a LateContext<'a, 'tcx>,
    set: HirIdSet,
    too_large_for_stack: u64,
}

impl_lint_pass!(BoxedLocal => [BOXED_LOCAL]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: visit::FnKind<'tcx>,
        _: &'tcx FnDecl,
        body: &'tcx Body,
        _: Span,
        hir_id: HirId,
    ) {
        // If the method is an impl for a trait, don't warn.
        let parent_id = cx.tcx.hir().get_parent_item(hir_id);
        let parent_node = cx.tcx.hir().find(parent_id);

        if let Some(Node::Item(item)) = parent_node {
            if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.node {
                return;
            }
        }

        let mut v = EscapeDelegate {
            cx,
            set: HirIdSet::default(),
            too_large_for_stack: self.too_large_for_stack,
        };

        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
        let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
        ExprUseVisitor::new(
            &mut v,
            cx.tcx,
            fn_def_id,
            cx.param_env,
            region_scope_tree,
            cx.tables,
            None,
        )
        .consume_body(body);

        for node in v.set {
            span_lint(
                cx,
                BOXED_LOCAL,
                cx.tcx.hir().span(node),
                "local variable doesn't need to be boxed here",
            );
        }
    }
}

impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
    fn consume(&mut self, _: HirId, _: Span, cmt: &cmt_<'tcx>, mode: ConsumeMode) {
        if let Categorization::Local(lid) = cmt.cat {
            if let Move(DirectRefMove) | Move(CaptureMove) = mode {
                // moved out or in. clearly can't be localized
                self.set.remove(&lid);
            }
        }
    }
    fn matched_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: MatchMode) {}
    fn consume_pat(&mut self, consume_pat: &Pat, cmt: &cmt_<'tcx>, _: ConsumeMode) {
        let map = &self.cx.tcx.hir();
        if map.is_argument(consume_pat.hir_id) {
            // Skip closure arguments
            if let Some(Node::Expr(..)) = map.find(map.get_parent_node(consume_pat.hir_id)) {
                return;
            }
            if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
                self.set.insert(consume_pat.hir_id);
            }
            return;
        }
        if let Categorization::Rvalue(..) = cmt.cat {
            if let Some(Node::Stmt(st)) = map.find(map.get_parent_node(cmt.hir_id)) {
                if let StmtKind::Local(ref loc) = st.node {
                    if let Some(ref ex) = loc.init {
                        if let ExprKind::Box(..) = ex.node {
                            if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
                                // let x = box (...)
                                self.set.insert(consume_pat.hir_id);
                            }
                            // TODO Box::new
                            // TODO vec![]
                            // TODO "foo".to_owned() and friends
                        }
                    }
                }
            }
        }
        if let Categorization::Local(lid) = cmt.cat {
            if self.set.contains(&lid) {
                // let y = x where x is known
                // remove x, insert y
                self.set.insert(consume_pat.hir_id);
                self.set.remove(&lid);
            }
        }
    }
    fn borrow(
        &mut self,
        _: HirId,
        _: Span,
        cmt: &cmt_<'tcx>,
        _: ty::Region<'_>,
        _: ty::BorrowKind,
        loan_cause: LoanCause,
    ) {
        if let Categorization::Local(lid) = cmt.cat {
            match loan_cause {
                // `x.foo()`
                // Used without autoderef-ing (i.e., `x.clone()`).
                LoanCause::AutoRef |

                // `&x`
                // `foo(&x)` where no extra autoref-ing is happening.
                LoanCause::AddrOf |

                // `match x` can move.
                LoanCause::MatchDiscriminant => {
                    self.set.remove(&lid);
                }

                // Do nothing for matches, etc. These can't escape.
                _ => {}
            }
        }
    }
    fn decl_without_init(&mut self, _: HirId, _: Span) {}
    fn mutate(&mut self, _: HirId, _: Span, _: &cmt_<'tcx>, _: MutateMode) {}
}

impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
    fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
        // Large types need to be boxed to avoid stack overflows.
        if ty.is_box() {
            self.cx.layout_of(ty.boxed_ty()).ok().map_or(0, |l| l.size.bytes()) > self.too_large_for_stack
        } else {
            false
        }
    }
}
<commit_msg>Fix breakage due to rust-lang/rust#61856<commit_after>use rustc::hir::intravisit as visit;
use rustc::hir::{self, *};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::middle::expr_use_visitor::*;
use rustc::middle::mem_categorization::{cmt_, Categorization};
use rustc::ty::layout::LayoutOf;
use rustc::ty::{self, Ty};
use rustc::util::nodemap::HirIdSet;
use rustc::{declare_tool_lint, impl_lint_pass};
use syntax::source_map::Span;

use crate::utils::span_lint;

#[derive(Copy, Clone)]
pub struct BoxedLocal {
    pub too_large_for_stack: u64,
}

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `Box<T>` where an unboxed `T` would
    /// work fine.
    ///
    /// **Why is this bad?** This is an unnecessary allocation, and bad for
    /// performance. It is only necessary to allocate if you wish to move the box
    /// into something.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn main() {
    ///     let x = Box::new(1);
    ///     foo(*x);
    ///     println!("{}", *x);
    /// }
    /// ```
    pub BOXED_LOCAL,
    perf,
    "using `Box<T>` where unnecessary"
}

fn is_non_trait_box(ty: Ty<'_>) -> bool {
    ty.is_box() && !ty.boxed_ty().is_trait()
}

struct EscapeDelegate<'a, 'tcx> {
    cx: &'a LateContext<'a, 'tcx>,
    set: HirIdSet,
    too_large_for_stack: u64,
}

impl_lint_pass!(BoxedLocal => [BOXED_LOCAL]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: visit::FnKind<'tcx>,
        _: &'tcx FnDecl,
        body: &'tcx Body,
        _: Span,
        hir_id: HirId,
    ) {
        // If the method is an impl for a trait, don't warn.
        let parent_id = cx.tcx.hir().get_parent_item(hir_id);
        let parent_node = cx.tcx.hir().find(parent_id);

        if let Some(Node::Item(item)) = parent_node {
            if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.node {
                return;
            }
        }

        let mut v = EscapeDelegate {
            cx,
            set: HirIdSet::default(),
            too_large_for_stack: self.too_large_for_stack,
        };

        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
        let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
        ExprUseVisitor::new(
            &mut v,
            cx.tcx,
            fn_def_id,
            cx.param_env,
            region_scope_tree,
            cx.tables,
            None,
        )
        .consume_body(body);

        for node in v.set {
            span_lint(
                cx,
                BOXED_LOCAL,
                cx.tcx.hir().span(node),
                "local variable doesn't need to be boxed here",
            );
        }
    }
}

// TODO: Replace with Map::is_argument(..) when it's fixed
fn is_argument(map: &hir::map::Map<'_>, id: HirId) -> bool {
    match map.find(id) {
        Some(Node::Binding(_)) => (),
        _ => return false,
    }

    match map.find(map.get_parent_node(id)) {
        Some(Node::Arg(_)) => true,
        _ => false,
    }
}

impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
    fn consume(&mut self, _: HirId, _: Span, cmt: &cmt_<'tcx>, mode: ConsumeMode) {
        if let Categorization::Local(lid) = cmt.cat {
            if let Move(DirectRefMove) | Move(CaptureMove) = mode {
                // moved out or in. clearly can't be localized
                self.set.remove(&lid);
            }
        }
    }
    fn matched_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: MatchMode) {}
    fn consume_pat(&mut self, consume_pat: &Pat, cmt: &cmt_<'tcx>, _: ConsumeMode) {
        let map = &self.cx.tcx.hir();
        if is_argument(map, consume_pat.hir_id) {
            // Skip closure arguments
            let parent_id = map.get_parent_node(consume_pat.hir_id);
            if let Some(Node::Expr(..)) = map.find(map.get_parent_node(parent_id)) {
                return;
            }

            if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
                self.set.insert(consume_pat.hir_id);
            }
            return;
        }
        if let Categorization::Rvalue(..) = cmt.cat {
            if let Some(Node::Stmt(st)) = map.find(map.get_parent_node(cmt.hir_id)) {
                if let StmtKind::Local(ref loc) = st.node {
                    if let Some(ref ex) = loc.init {
                        if let ExprKind::Box(..) = ex.node {
                            if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
                                // let x = box (...)
                                self.set.insert(consume_pat.hir_id);
                            }
                            // TODO Box::new
                            // TODO vec![]
                            // TODO "foo".to_owned() and friends
                        }
                    }
                }
            }
        }
        if let Categorization::Local(lid) = cmt.cat {
            if self.set.contains(&lid) {
                // let y = x where x is known
                // remove x, insert y
                self.set.insert(consume_pat.hir_id);
                self.set.remove(&lid);
            }
        }
    }
    fn borrow(
        &mut self,
        _: HirId,
        _: Span,
        cmt: &cmt_<'tcx>,
        _: ty::Region<'_>,
        _: ty::BorrowKind,
        loan_cause: LoanCause,
    ) {
        if let Categorization::Local(lid) = cmt.cat {
            match loan_cause {
                // `x.foo()`
                // Used without autoderef-ing (i.e., `x.clone()`).
                LoanCause::AutoRef |

                // `&x`
                // `foo(&x)` where no extra autoref-ing is happening.
                LoanCause::AddrOf |

                // `match x` can move.
                LoanCause::MatchDiscriminant => {
                    self.set.remove(&lid);
                }

                // Do nothing for matches, etc. These can't escape.
                _ => {}
            }
        }
    }
    fn decl_without_init(&mut self, _: HirId, _: Span) {}
    fn mutate(&mut self, _: HirId, _: Span, _: &cmt_<'tcx>, _: MutateMode) {}
}

impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
    fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
        // Large types need to be boxed to avoid stack overflows.
        if ty.is_box() {
            self.cx.layout_of(ty.boxed_ty()).ok().map_or(0, |l| l.size.bytes()) > self.too_large_for_stack
        } else {
            false
        }
    }
}
<|endoftext|>


<commit_before>extern crate diffgeom;
extern crate gr_engine;
#[macro_use]
extern crate generic_array;
extern crate numeric_algs;

use diffgeom::coordinates::Point;
use diffgeom::tensors::Vector;
use gr_engine::coord_systems::schwarzschild::{EddingtonFinkelstein, Mass};
use gr_engine::numeric::StateVector;
use gr_engine::particle::Particle;
use numeric_algs::integration::{DPIntegrator, Integrator, StepSize};
use std::f64::consts::PI;

struct Sun;
impl Mass for Sun {
    fn mass() -> f64 {
        M
    }
}

type Coords = EddingtonFinkelstein<Sun>;

const M: f64 = 4.9e-6; // mass of the Sun in seconds, with c = G = 1
const D: f64 = 2.33; // radius of the Sun in seconds
const YE: f64 = 498.67; // Earth "y" coordinate in seconds
const YV: f64 = 370.7; // Venus "y" coordinate in seconds

fn u(t: f64, r: f64) -> f64 {
    t + r + (0.5 * (r - 2.0 * M) / M).ln() * 2.0 * M
}

fn t(u: f64, r: f64) -> f64 {
    u - r - (0.5 * (r - 2.0 * M) / M).ln() * 2.0 * M
}

fn main() {
    let u0 = (D * D * D / (D - M * 2.0)).sqrt();
    let r_e = (D * D + YE * YE).sqrt();
    let r_v = (D * D + YV * YV).sqrt();

    let t_flat = 2.0 * (YE + YV);

    let start_point = Point::<Coords>::new(arr![f64; u(0.0, D), D, PI / 2.0, 0.0]);
    let u_init1 = Vector::<Coords>::new(start_point.clone(), arr![f64; u0, 0.0, 0.0, 1.0]);
    let u_init2 = Vector::<Coords>::new(start_point.clone(), arr![f64; -u0, 0.0, 0.0, -1.0]);

    let mut photon1 = Particle::new(start_point.clone(), u_init1);
    let mut photon2 = Particle::new(start_point.clone(), u_init2);

    let mut integrator1 = DPIntegrator::<Particle<Coords>>::new(0.01, 0.0001, 0.1, 1e-12);
    let mut integrator2 = DPIntegrator::<Particle<Coords>>::new(0.01, 0.0001, 0.1, 1e-12);

    let mut last_pos = photon1.get_pos().clone();
    println!("Propagating the first photon...");

    let mut i = 1;
    while photon1.get_pos()[1] < r_e {
        last_pos = photon1.get_pos().clone();
        integrator1.propagate_in_place(&mut photon1, Particle::derivative, StepSize::UseDefault);
        i += 1;
        if i % 100 == 0 {
            println!("Iteration {}... r = {}", i, photon1.get_pos()[1]);
        }
    }
    let pos = photon1.get_pos().clone();
    let pos = StateVector(arr![f64; pos[0], pos[1], pos[2], pos[3]]);
    let last_pos = StateVector(arr![f64; last_pos[0], last_pos[1], last_pos[2], last_pos[3]]);
    let coeff = (r_e - last_pos.0[1]) / (pos.0[1] - last_pos.0[1]);
    let last_pos = last_pos + (pos - last_pos) * coeff;
    let t1 = t(last_pos.0[0], last_pos.0[1]);

    let mut last_pos = photon2.get_pos().clone();
    println!("Propagating the second photon...");

    let mut i = 1;
    while photon2.get_pos()[1] < r_v {
        last_pos = photon2.get_pos().clone();
        integrator2.propagate_in_place(&mut photon2, Particle::derivative, StepSize::UseDefault);
        i += 1;
        if i % 100 == 0 {
            println!("Iteration {}... r = {}", i, photon2.get_pos()[1]);
        }
    }
    let pos = photon2.get_pos().clone();
    let pos = StateVector(arr![f64; pos[0], pos[1], pos[2], pos[3]]);
    let last_pos = StateVector(arr![f64; last_pos[0], last_pos[1], last_pos[2], last_pos[3]]);
    let coeff = (r_v - last_pos.0[1]) / (pos.0[1] - last_pos.0[1]);
    let last_pos = last_pos + (pos - last_pos) * coeff;
    let t2 = t(last_pos.0[0], last_pos.0[1]);

    println!("Propagation finished.");
    println!("t1 = {}", t1);
    println!("t2 = {}", t2);

    let dt = (t1 - t2) * 2.0 * (1.0 - 2.0 * M / r_e).sqrt();
    println!("dt = {}", dt);
    println!("delay = {}", dt - t_flat);
}
<commit_msg>Simplify the Shapiro example by using the Schwarzschild coordinates<commit_after>extern crate diffgeom;
extern crate gr_engine;
#[macro_use]
extern crate generic_array;
extern crate numeric_algs;

use diffgeom::coordinates::Point;
use diffgeom::tensors::Vector;
use gr_engine::coord_systems::schwarzschild::{Mass, Schwarzschild};
use gr_engine::numeric::StateVector;
use gr_engine::particle::Particle;
use numeric_algs::integration::{DPIntegrator, Integrator, StepSize};
use std::f64::consts::PI;

struct Sun;
impl Mass for Sun {
    fn mass() -> f64 {
        M
    }
}

type Coords = Schwarzschild<Sun>;

const M: f64 = 4.9e-6; // mass of the Sun in seconds, with c = G = 1
const D: f64 = 2.33; // radius of the Sun in seconds
const YE: f64 = 498.67; // Earth "y" coordinate in seconds
const YV: f64 = 370.7; // Venus "y" coordinate in seconds

fn main() {
    let u0 = (D * D * D / (D - M * 2.0)).sqrt();
    let r_e = (D * D + YE * YE).sqrt();
    let r_v = (D * D + YV * YV).sqrt();

    let t_flat = 2.0 * (YE + YV);

    let start_point = Point::<Coords>::new(arr![f64; 0.0, D, PI / 2.0, 0.0]);
    let u_init1 = Vector::<Coords>::new(start_point.clone(), arr![f64; u0, 0.0, 0.0, 1.0]);
    let u_init2 = Vector::<Coords>::new(start_point.clone(), arr![f64; -u0, 0.0, 0.0, -1.0]);

    let mut photon1 = Particle::new(start_point.clone(), u_init1);
    let mut photon2 = Particle::new(start_point.clone(), u_init2);

    let mut integrator1 = DPIntegrator::<Particle<Coords>>::new(0.01, 0.0001, 0.1, 1e-12);
    let mut integrator2 = DPIntegrator::<Particle<Coords>>::new(0.01, 0.0001, 0.1, 1e-12);

    let mut last_pos = photon1.get_pos().clone();
    println!("Propagating the first photon...");

    let mut i = 1;
    while photon1.get_pos()[1] < r_e {
        last_pos = photon1.get_pos().clone();
        integrator1.propagate_in_place(&mut photon1, Particle::derivative, StepSize::UseDefault);
        i += 1;
        if i % 100 == 0 {
            println!("Iteration {}... r = {}", i, photon1.get_pos()[1]);
        }
    }
    let pos = photon1.get_pos().clone();
    let pos = StateVector(arr![f64; pos[0], pos[1], pos[2], pos[3]]);
    let last_pos = StateVector(arr![f64; last_pos[0], last_pos[1], last_pos[2], last_pos[3]]);
    let coeff = (r_e - last_pos.0[1]) / (pos.0[1] - last_pos.0[1]);
    let last_pos = last_pos + (pos - last_pos) * coeff;
    let t1 = last_pos.0[0];

    let mut last_pos = photon2.get_pos().clone();
    println!("Propagating the second photon...");

    let mut i = 1;
    while photon2.get_pos()[1] < r_v {
        last_pos = photon2.get_pos().clone();
        integrator2.propagate_in_place(&mut photon2, Particle::derivative, StepSize::UseDefault);
        i += 1;
        if i % 100 == 0 {
            println!("Iteration {}... r = {}", i, photon2.get_pos()[1]);
        }
    }
    let pos = photon2.get_pos().clone();
    let pos = StateVector(arr![f64; pos[0], pos[1], pos[2], pos[3]]);
    let last_pos = StateVector(arr![f64; last_pos[0], last_pos[1], last_pos[2], last_pos[3]]);
    let coeff = (r_v - last_pos.0[1]) / (pos.0[1] - last_pos.0[1]);
    let last_pos = last_pos + (pos - last_pos) * coeff;
    let t2 = last_pos.0[0];

    println!("Propagation finished.");
    println!("t1 = {}", t1);
    println!("t2 = {}", t2);

    let dt = (t1 - t2) * 2.0 * (1.0 - 2.0 * M / r_e).sqrt();
    println!("dt = {}", dt);
    println!("delay = {}", dt - t_flat);
}
<|endoftext|>


<commit_before>//https://github.com/andelf/rust-postgis
use postgis as geom;
use postgis::{SRID,WGS84};
use core::screen;

#[allow(missing_copy_implementations)]
#[allow(non_camel_case_types)]
pub enum EPSG_3857 {}

impl SRID for EPSG_3857 {
    fn as_srid() -> Option<i32> { Some(3857) }
}

pub struct Extent {
    pub minx: f64,
    pub miny: f64,
    pub maxx: f64,
    pub maxy: f64
}

impl Extent {
    /// Convert geometry to tile relative coordinates
    fn geom_in_tile_extent(&self, tile_size: u32, geom: geom::Point<EPSG_3857>) -> screen::Point {
        let x_span = self.maxx - self.minx;
        let y_span = self.maxy - self.miny;
        screen::Point {
            x: ((geom.x-self.minx) * tile_size as f64 / x_span) as i32,
            y: ((geom.y-self.miny) * tile_size as f64 / y_span) as i32 }
    }
}

#[test]
fn test_geom_in_tile_extent() {
    //let zh_mercator = geom::Point::<EPSG_3857>::new(949398.0, 6002729.0);
    let zh_mercator = geom::Point::<EPSG_3857>::new(960000.0, 6002729.0);
    //let zh_wgs84 = geom::Point::<WGS84>::new(47.3703149, 8.5285874);
    let tile_extent = Extent {minx: 958826.08, miny: 5987771.04, maxx: 978393.96, maxy: 6007338.92};
    let screen_pt = tile_extent.geom_in_tile_extent(
        4096, zh_mercator);
    assert_eq!(screen_pt, screen::Point { x: 245, y: 3131 });
    //assert_eq!(screen_pt.encode().0, &[9,490,6262]);
}
<commit_msg>Grid struct with tile functions<commit_after>//https://github.com/andelf/rust-postgis
use postgis as geom;
use postgis::{SRID,WGS84};
use core::screen;
use std::f64::consts;

#[allow(missing_copy_implementations)]
#[allow(non_camel_case_types)]
pub enum EPSG_3857 {}

impl SRID for EPSG_3857 {
    fn as_srid() -> Option<i32> { Some(3857) }
}

#[derive(PartialEq,Debug)]
pub struct LngLat {
    pub lon: f64,
    pub lat: f64,
}

#[derive(PartialEq,Debug)]
pub struct Extent {
    pub minx: f64,
    pub miny: f64,
    pub maxx: f64,
    pub maxy: f64,
}

impl Extent {
    /// Convert geometry to tile relative coordinates
    fn geom_in_tile_extent(&self, tile_size: u32, geom: geom::Point<EPSG_3857>) -> screen::Point {
        let x_span = self.maxx - self.minx;
        let y_span = self.maxy - self.miny;
        screen::Point {
            x: ((geom.x-self.minx) * tile_size as f64 / x_span) as i32,
            y: ((geom.y-self.miny) * tile_size as f64 / y_span) as i32 }
    }
}

#[test]
fn test_geom_in_tile_extent() {
    //let zh_mercator = geom::Point::<EPSG_3857>::new(949398.0, 6002729.0);
    let zh_mercator = geom::Point::<EPSG_3857>::new(960000.0, 6002729.0);
    //let zh_wgs84 = geom::Point::<WGS84>::new(47.3703149, 8.5285874);
    let tile_extent = Extent {minx: 958826.08, miny: 5987771.04, maxx: 978393.96, maxy: 6007338.92};
    let screen_pt = tile_extent.geom_in_tile_extent(
        4096, zh_mercator);
    assert_eq!(screen_pt, screen::Point { x: 245, y: 3131 });
    //assert_eq!(screen_pt.encode().0, &[9,490,6262]);
}

// Credits: MapCache by Thomas Bonfort (http://mapserver.org/mapcache/)
pub struct Grid {
    /// The width and height of an individual tile, in pixels. Must be specified as positive integers separated by a space character.
    width: u16,
    height: u16,
    /// The geographical extent covered by the grid, in ground units (e.g. meters, degrees, feet, etc.). Must be specified as 4 floating point numbers ordered as minx, miny, maxx, maxy.
    /// The (minx,miny) point defines the origin of the grid, i.e. the pixel at the bottom left of the bottom-left most tile is always placed on the (minx,miny) geographical point.
    /// The (maxx,maxy) point is used to determine how many tiles there are for each zoom level.
    extent: Extent,
    //srs: SRID,
    //units: m/dd/ft
    /// This is a list of resolutions for each of the zoom levels defined by the grid. This must be supplied as a list of positive floating point values, ordered from largest to smallest.
    /// The largest value will correspond to the grid’s zoom level 0. Resolutions are expressed in “units-per-pixel”, depending on the unit used by the grid (e.g. resolutions are in meters per pixel for most grids used in webmapping).
    resolutions: Vec<f64>
    //origin: top-left, bottom-left, top-right and bottom-right
}

/// Returns the upper left (lon, lat) of a tile
// Credits: Mercantile by Sean C. Gillies (https://github.com/mapbox/mercantile)
fn ul(xtile: u16, ytile: u16, zoom: u16) -> LngLat {
    let n = (zoom as f64).exp2();
    let lon_deg = xtile as f64 / n * 360.0 - 180.0;
    let lat_rad = (consts::PI * (1.0_f64 - 2.0_f64 * ytile as f64 / n)).sinh().atan();
    let lat_deg = lat_rad.to_degrees();
    LngLat {lon: lon_deg, lat: lat_deg}
}

/// Returns the Spherical Mercator (x, y) in meters
fn xy(lon: f64, lat: f64) -> (f64, f64) {
    //lng, lat = truncate_lnglat(lng, lat)
    let x = 6378137.0_f64 * lon.to_radians();
    let y = 6378137.0_f64 *
        ((consts::PI*0.25) + (0.5_f64 * lat.to_radians())).tan().ln();
    (x, y)
}

#[test]
fn test_ul() {
    let lnglat = ul(486, 332, 10);
    assert_eq!(lnglat, LngLat {lon: -9.140625, lat: 53.33087298301705});
}

#[test]
fn test_xy() {
    let ul = ul(486, 332, 10);
    let xy_ = xy(ul.lon, ul.lat);
    assert_eq!(xy_, (-1017529.7205322663, 7044436.526761846));
    assert_eq!(xy(0.0, 0.0), (0.0, -0.0000000007081154551613622));
}

impl Grid {
    /// Returns the (lon, lat) bounding box of a tile
    pub fn tile_bounds(&self, xtile: u16, ytile: u16, zoom: u16) -> Extent {
        let a = ul(xtile, ytile, zoom);
        let b = ul(xtile+1, ytile+1, zoom);
        Extent {minx: a.lon, miny: b.lat, maxx: b.lon, maxy: a.lat}
    }
    /// Returns the Spherical Mercator bounding box of a tile
    pub fn tile_extent(&self, xtile: u16, ytile: u16, zoom: u16) -> Extent {
        let a = ul(xtile, ytile, zoom);
        let (ax, ay) = xy(a.lon, a.lat);
        let b = ul(xtile+1, ytile+1, zoom);
        let (bx, by) = xy(b.lon, b.lat);
        Extent {minx: ax, miny: by, maxx: bx, maxy: ay}
    }
}

#[test]
fn test_bbox() {
    let grid = Grid {width: 256, height: 256, extent: Extent {minx: 0.0, miny: 0.0, maxx: 0.0, maxy: 0.0}, resolutions: Vec::new()};

    let bbox = grid.tile_bounds(486, 332, 10);
    assert_eq!(bbox, Extent {minx: -9.140625, miny: 53.120405283106564, maxx: -8.7890625, maxy: 53.33087298301705});
    //Mercantile: miny: 53.12040528310657

    let extent = grid.tile_extent(486, 332, 10);
    assert_eq!(extent, Extent {minx: -1017529.7205322663, miny: 7005300.768279833, maxx: -978393.962050256, maxy: 7044436.526761846});
}
<|endoftext|>


<commit_before>use std::default::Default;
use num::{Float};
use image;
use glium::{self, texture, framebuffer, Surface};
use glium::LinearBlendingFactor::*;
use super::{CanvasMagnify};
use ::{V2, Rect};
use ::rgb::{to_srgb};

pub struct Renderer<'a> {
    /// Canvas size.
    size: V2<u32>,
    /// Rendering device resolution.
    resolution: V2<u32>,
    /// Shader for drawing atlas images.
    sprite_shader: glium::Program,
    /// Shader for blitting the canvas texture to screen.
    blit_shader: glium::Program,
    /// Atlas texture, contains all the sprites. Calx is a low-rent operation
    /// so we only have one.
    atlas: texture::Texture2d,
    /// Render target texture.
    buffer: texture::Texture2d,
    depth: framebuffer::DepthRenderBuffer,
    params: glium::DrawParameters<'a>,
    magnify: CanvasMagnify,
}

impl<'a> Renderer<'a> {
    pub fn new<'b, T>(
        size: V2<u32>, display: &glium::Display,
        texture_image: T, magnify: CanvasMagnify) -> Renderer<'a>
        where T: texture::Texture2dDataSource<'b> {

        let sprite_shader = glium::Program::from_source(display,
            include_str!("sprite.vert"),
            include_str!("sprite.frag"),
            None).unwrap();
        let blit_shader = glium::Program::from_source(display,
            include_str!("blit.vert"),
            include_str!("blit.frag"),
            None).unwrap();
        let atlas = texture::Texture2d::new(display, texture_image).unwrap();

        let buffer = texture::Texture2d::empty(
            display, size.0, size.1).unwrap();
        let depth = framebuffer::DepthRenderBuffer::new(
            display, texture::DepthFormat::F32, size.0, size.1);

        let mut params: glium::DrawParameters = Default::default();
        params.backface_culling = glium::BackfaceCullingMode::CullCounterClockWise;
        params.depth_test = glium::DepthTest::IfLessOrEqual;
        params.depth_write = true;
        params.blending_function = Some(glium::BlendingFunction::Addition {
            source: SourceAlpha, destination: OneMinusSourceAlpha });

        Renderer {
            size: size,
            resolution: size,
            sprite_shader: sprite_shader,
            blit_shader: blit_shader,
            atlas: atlas,
            buffer: buffer,
            depth: depth,
            params: params,
            magnify: magnify,
        }
    }

    /// Draw sprites on target.
    fn draw_sprites<S>(&self, display: &glium::Display, target: &mut S,
                       vertices: Vec<Vertex>, indices: Vec<u16>)
        where S: glium::Surface {

        // Extract the geometry accumulation buffers and convert into
        // temporary Glium buffers.
        let vertices = glium::VertexBuffer::new(display, &vertices).unwrap();
        let indices = glium::IndexBuffer::new(
            display, glium::index::PrimitiveType::TrianglesList, &indices).unwrap();

        let uniforms = glium::uniforms::UniformsStorage::new("tex",
            glium::uniforms::Sampler(&self.atlas, glium::uniforms::SamplerBehavior {
                magnify_filter: glium::uniforms::MagnifySamplerFilter::Nearest,
                .. Default::default() }));

        target.draw(&vertices, &indices, &self.sprite_shader, &uniforms, &self.params).unwrap();
    }

    /// Blit the buffer texture to target.
    fn blit_buffer<S>(&self, display: &glium::Display, target: &mut S)
        where S: glium::Surface {
        // TODO: Pixel-perfect scaling to target dimensions.
        //
        let Rect(V2(sx, sy), V2(sw, sh)) = match self.magnify {
            CanvasMagnify::PixelPerfect => pixel_perfect(self.size, self.resolution),
            _ => preserve_aspect(self.size, self.resolution),
        };

        let vertices = {
            #[derive(Copy, Clone)]
            struct BlitVertex { pos: [f32; 2], tex_coord: [f32; 2] }
            implement_vertex!(BlitVertex, pos, tex_coord);

            glium::VertexBuffer::new(display,
            &[
                BlitVertex { pos: [sx,    sy   ], tex_coord: [0.0, 0.0] },
                BlitVertex { pos: [sx+sw, sy   ], tex_coord: [1.0, 0.0] },
                BlitVertex { pos: [sx+sw, sy+sh], tex_coord: [1.0, 1.0] },
                BlitVertex { pos: [sx,    sy+sh], tex_coord: [0.0, 1.0] },
            ]).unwrap()
        };

        let indices = glium::IndexBuffer::new(display,
            glium::index::PrimitiveType::TrianglesList, &[0u16, 1, 2, 0, 2, 3]).unwrap();

        let mut params: glium::DrawParameters = Default::default();
        // Set an explicit viewport to apply the custom resolution that fixes
        // pixel perfect rounding errors.
        params.viewport = Some(glium::Rect{
            left: 0, bottom: 0,
            width: self.resolution.0,
            height: self.resolution.1 });

        let mag_filter = match self.magnify {
            CanvasMagnify::Smooth => glium::uniforms::MagnifySamplerFilter::Linear,
            _ => glium::uniforms::MagnifySamplerFilter::Nearest
        };

        let uniforms = glium::uniforms::UniformsStorage::new("tex",
            glium::uniforms::Sampler(&self.buffer, glium::uniforms::SamplerBehavior {
                magnify_filter: mag_filter,
                minify_filter: glium::uniforms::MinifySamplerFilter::Linear,
                .. Default::default() }));

        target.draw(&vertices, &indices, &self.blit_shader, &uniforms, &params).unwrap();
    }

    /// Call at the start of drawing
    pub fn init(&mut self, display: &glium::Display) {
        let mut target = framebuffer::SimpleFrameBuffer::with_depth_buffer(
            display, &self.buffer, &self.depth);
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.clear_depth(1.0);
    }

    /// Draw a geometry buffer.
    pub fn draw(&mut self, display: &glium::Display,
                vertices: Vec<Vertex>, indices: Vec<u16>) {
        // Render the graphics to a texture to keep the pixels pure and
        // untainted.
        let mut sprite_target = framebuffer::SimpleFrameBuffer::with_depth_buffer(
            display, &self.buffer, &self.depth);
        self.draw_sprites(display, &mut sprite_target, vertices, indices);
    }

    /// Show the drawn geometry on screen.
    pub fn show<S>(&mut self, display: &glium::Display, target: &mut S)
        where S: glium::Surface
    {
        let (w, h) = display.get_framebuffer_dimensions();
        // Clip viewport dimensions to even to prevent rounding errors in
        // pixel perfect scaling.
        self.resolution = V2(w & !1, h & !1);
        // Render the texture to screen.
        self.blit_buffer(display, target);
    }

    /// Map screen position (eg. of a mouse cursor) to canvas position.
    pub fn screen_to_canvas(&self, V2(sx, sy): V2<i32>) -> V2<i32> {
        let Rect(V2(rx, ry), V2(rw, rh)) = pixel_perfect(self.size, self.resolution);
        // Transform to device coordinates.
        let sx = sx as f32 * 2.0 / self.resolution.0 as f32 - 1.0;
        let sy = sy as f32 * 2.0 / self.resolution.1 as f32 - 1.0;

        V2(((sx - rx) * self.size.0 as f32 / rw) as i32,
           ((sy - ry) * self.size.1 as f32 / rh) as i32)
    }

    pub fn canvas_pixels(&self) -> image::ImageBuffer<image::Rgb<u8>, Vec<u8>> {
        let mut ret = self.buffer.read::<image::DynamicImage>().to_rgb();

        // Convert to sRGB
        // XXX: Probably horribly slow, can we make OpenGL do this?
        for p in ret.pixels_mut() {
            p.data[0] = (to_srgb(p.data[0] as f32 / 255.0) * 255.0).round() as u8;
            p.data[1] = (to_srgb(p.data[1] as f32 / 255.0) * 255.0).round() as u8;
            p.data[2] = (to_srgb(p.data[2] as f32 / 255.0) * 255.0).round() as u8;
        }

        ret
    }
}

#[derive(Copy, Clone)]
/// Geometry vertex in on-screen graphics.
pub struct Vertex {
    /// Coordinates on screen
    pub pos: [f32; 3],
    /// Texture coordinates
    pub tex_coord: [f32; 2],
    /// Color for the light parts of the texture
    pub color: [f32; 4],
    /// Color for the dark parts of the texture
    pub back_color: [f32; 4],
}
implement_vertex!(Vertex, pos, tex_coord, color, back_color);

/// A pixel perfect centered and scaled rectangle of resolution dim in a
/// window of size area, mapped to OpenGL device coordinates.
#[inline(always)]
fn pixel_perfect(canvas: V2<u32>, window: V2<u32>) -> Rect<f32> {
    // Scale based on whichever of X or Y axis is the tighter fit.
    let mut scale = (window.0 as f32 / canvas.0 as f32)
        .min(window.1 as f32 / canvas.1 as f32);

    if scale > 1.0 {
        // Snap to pixel scale if more than 1 window pixel per canvas pixel.
        scale = scale.floor();
    }

    let dim = V2((scale * canvas.0 as f32) * 2.0 / window.0 as f32,
                 (scale * canvas.1 as f32) * 2.0 / window.1 as f32);
    let offset = -dim / 2.0;
    Rect(offset, dim)
}

#[inline(always)]
fn preserve_aspect(canvas: V2<u32>, window: V2<u32>) -> Rect<f32> {
    // Scale based on whichever of X or Y axis is the tighter fit.
    let scale = (window.0 as f32 / canvas.0 as f32)
        .min(window.1 as f32 / canvas.1 as f32);

    let dim = V2((scale * canvas.0 as f32) * 2.0 / window.0 as f32,
                 (scale * canvas.1 as f32) * 2.0 / window.1 as f32);
    let offset = -dim / 2.0;
    Rect(offset, dim)
}
<commit_msg>Clear the borders around the canvas as well<commit_after>use std::default::Default;
use num::{Float};
use image;
use glium::{self, texture, framebuffer, Surface};
use glium::LinearBlendingFactor::*;
use super::{CanvasMagnify};
use ::{V2, Rect};
use ::rgb::{to_srgb};

pub struct Renderer<'a> {
    /// Canvas size.
    size: V2<u32>,
    /// Rendering device resolution.
    resolution: V2<u32>,
    /// Shader for drawing atlas images.
    sprite_shader: glium::Program,
    /// Shader for blitting the canvas texture to screen.
    blit_shader: glium::Program,
    /// Atlas texture, contains all the sprites. Calx is a low-rent operation
    /// so we only have one.
    atlas: texture::Texture2d,
    /// Render target texture.
    buffer: texture::Texture2d,
    depth: framebuffer::DepthRenderBuffer,
    params: glium::DrawParameters<'a>,
    magnify: CanvasMagnify,
}

impl<'a> Renderer<'a> {
    pub fn new<'b, T>(
        size: V2<u32>, display: &glium::Display,
        texture_image: T, magnify: CanvasMagnify) -> Renderer<'a>
        where T: texture::Texture2dDataSource<'b> {

        let sprite_shader = glium::Program::from_source(display,
            include_str!("sprite.vert"),
            include_str!("sprite.frag"),
            None).unwrap();
        let blit_shader = glium::Program::from_source(display,
            include_str!("blit.vert"),
            include_str!("blit.frag"),
            None).unwrap();
        let atlas = texture::Texture2d::new(display, texture_image).unwrap();

        let buffer = texture::Texture2d::empty(
            display, size.0, size.1).unwrap();
        let depth = framebuffer::DepthRenderBuffer::new(
            display, texture::DepthFormat::F32, size.0, size.1);

        let mut params: glium::DrawParameters = Default::default();
        params.backface_culling = glium::BackfaceCullingMode::CullCounterClockWise;
        params.depth_test = glium::DepthTest::IfLessOrEqual;
        params.depth_write = true;
        params.blending_function = Some(glium::BlendingFunction::Addition {
            source: SourceAlpha, destination: OneMinusSourceAlpha });

        Renderer {
            size: size,
            resolution: size,
            sprite_shader: sprite_shader,
            blit_shader: blit_shader,
            atlas: atlas,
            buffer: buffer,
            depth: depth,
            params: params,
            magnify: magnify,
        }
    }

    /// Draw sprites on target.
    fn draw_sprites<S>(&self, display: &glium::Display, target: &mut S,
                       vertices: Vec<Vertex>, indices: Vec<u16>)
        where S: glium::Surface {

        // Extract the geometry accumulation buffers and convert into
        // temporary Glium buffers.
        let vertices = glium::VertexBuffer::new(display, &vertices).unwrap();
        let indices = glium::IndexBuffer::new(
            display, glium::index::PrimitiveType::TrianglesList, &indices).unwrap();

        let uniforms = glium::uniforms::UniformsStorage::new("tex",
            glium::uniforms::Sampler(&self.atlas, glium::uniforms::SamplerBehavior {
                magnify_filter: glium::uniforms::MagnifySamplerFilter::Nearest,
                .. Default::default() }));

        target.draw(&vertices, &indices, &self.sprite_shader, &uniforms, &self.params).unwrap();
    }

    /// Blit the buffer texture to target.
    fn blit_buffer<S>(&self, display: &glium::Display, target: &mut S)
        where S: glium::Surface {
        // TODO: Pixel-perfect scaling to target dimensions.
        //
        let Rect(V2(sx, sy), V2(sw, sh)) = match self.magnify {
            CanvasMagnify::PixelPerfect => pixel_perfect(self.size, self.resolution),
            _ => preserve_aspect(self.size, self.resolution),
        };

        let vertices = {
            #[derive(Copy, Clone)]
            struct BlitVertex { pos: [f32; 2], tex_coord: [f32; 2] }
            implement_vertex!(BlitVertex, pos, tex_coord);

            glium::VertexBuffer::new(display,
            &[
                BlitVertex { pos: [sx,    sy   ], tex_coord: [0.0, 0.0] },
                BlitVertex { pos: [sx+sw, sy   ], tex_coord: [1.0, 0.0] },
                BlitVertex { pos: [sx+sw, sy+sh], tex_coord: [1.0, 1.0] },
                BlitVertex { pos: [sx,    sy+sh], tex_coord: [0.0, 1.0] },
            ]).unwrap()
        };

        let indices = glium::IndexBuffer::new(display,
            glium::index::PrimitiveType::TrianglesList, &[0u16, 1, 2, 0, 2, 3]).unwrap();

        let mut params: glium::DrawParameters = Default::default();
        // Set an explicit viewport to apply the custom resolution that fixes
        // pixel perfect rounding errors.
        params.viewport = Some(glium::Rect{
            left: 0, bottom: 0,
            width: self.resolution.0,
            height: self.resolution.1 });

        let mag_filter = match self.magnify {
            CanvasMagnify::Smooth => glium::uniforms::MagnifySamplerFilter::Linear,
            _ => glium::uniforms::MagnifySamplerFilter::Nearest
        };

        let uniforms = glium::uniforms::UniformsStorage::new("tex",
            glium::uniforms::Sampler(&self.buffer, glium::uniforms::SamplerBehavior {
                magnify_filter: mag_filter,
                minify_filter: glium::uniforms::MinifySamplerFilter::Linear,
                .. Default::default() }));

        target.draw(&vertices, &indices, &self.blit_shader, &uniforms, &params).unwrap();
    }

    /// Call at the start of drawing
    pub fn init(&mut self, display: &glium::Display) {
        let mut target = framebuffer::SimpleFrameBuffer::with_depth_buffer(
            display, &self.buffer, &self.depth);
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.clear_depth(1.0);
    }

    /// Draw a geometry buffer.
    pub fn draw(&mut self, display: &glium::Display,
                vertices: Vec<Vertex>, indices: Vec<u16>) {
        // Render the graphics to a texture to keep the pixels pure and
        // untainted.
        let mut sprite_target = framebuffer::SimpleFrameBuffer::with_depth_buffer(
            display, &self.buffer, &self.depth);
        self.draw_sprites(display, &mut sprite_target, vertices, indices);
    }

    /// Show the drawn geometry on screen.
    pub fn show<S>(&mut self, display: &glium::Display, target: &mut S)
        where S: glium::Surface
    {
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.clear_depth(1.0);
        let (w, h) = display.get_framebuffer_dimensions();
        // Clip viewport dimensions to even to prevent rounding errors in
        // pixel perfect scaling.
        self.resolution = V2(w & !1, h & !1);
        // Render the texture to screen.
        self.blit_buffer(display, target);
    }

    /// Map screen position (eg. of a mouse cursor) to canvas position.
    pub fn screen_to_canvas(&self, V2(sx, sy): V2<i32>) -> V2<i32> {
        let Rect(V2(rx, ry), V2(rw, rh)) = pixel_perfect(self.size, self.resolution);
        // Transform to device coordinates.
        let sx = sx as f32 * 2.0 / self.resolution.0 as f32 - 1.0;
        let sy = sy as f32 * 2.0 / self.resolution.1 as f32 - 1.0;

        V2(((sx - rx) * self.size.0 as f32 / rw) as i32,
           ((sy - ry) * self.size.1 as f32 / rh) as i32)
    }

    pub fn canvas_pixels(&self) -> image::ImageBuffer<image::Rgb<u8>, Vec<u8>> {
        let mut ret = self.buffer.read::<image::DynamicImage>().to_rgb();

        // Convert to sRGB
        // XXX: Probably horribly slow, can we make OpenGL do this?
        for p in ret.pixels_mut() {
            p.data[0] = (to_srgb(p.data[0] as f32 / 255.0) * 255.0).round() as u8;
            p.data[1] = (to_srgb(p.data[1] as f32 / 255.0) * 255.0).round() as u8;
            p.data[2] = (to_srgb(p.data[2] as f32 / 255.0) * 255.0).round() as u8;
        }

        ret
    }
}

#[derive(Copy, Clone)]
/// Geometry vertex in on-screen graphics.
pub struct Vertex {
    /// Coordinates on screen
    pub pos: [f32; 3],
    /// Texture coordinates
    pub tex_coord: [f32; 2],
    /// Color for the light parts of the texture
    pub color: [f32; 4],
    /// Color for the dark parts of the texture
    pub back_color: [f32; 4],
}
implement_vertex!(Vertex, pos, tex_coord, color, back_color);

/// A pixel perfect centered and scaled rectangle of resolution dim in a
/// window of size area, mapped to OpenGL device coordinates.
#[inline(always)]
fn pixel_perfect(canvas: V2<u32>, window: V2<u32>) -> Rect<f32> {
    // Scale based on whichever of X or Y axis is the tighter fit.
    let mut scale = (window.0 as f32 / canvas.0 as f32)
        .min(window.1 as f32 / canvas.1 as f32);

    if scale > 1.0 {
        // Snap to pixel scale if more than 1 window pixel per canvas pixel.
        scale = scale.floor();
    }

    let dim = V2((scale * canvas.0 as f32) * 2.0 / window.0 as f32,
                 (scale * canvas.1 as f32) * 2.0 / window.1 as f32);
    let offset = -dim / 2.0;
    Rect(offset, dim)
}

#[inline(always)]
fn preserve_aspect(canvas: V2<u32>, window: V2<u32>) -> Rect<f32> {
    // Scale based on whichever of X or Y axis is the tighter fit.
    let scale = (window.0 as f32 / canvas.0 as f32)
        .min(window.1 as f32 / canvas.1 as f32);

    let dim = V2((scale * canvas.0 as f32) * 2.0 / window.0 as f32,
                 (scale * canvas.1 as f32) * 2.0 / window.1 as f32);
    let offset = -dim / 2.0;
    Rect(offset, dim)
}
<|endoftext|>


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

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use std::path::Path;

use libc::{c_ulong};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_pes_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        let mut ffi_size = buffer_size as c_ulong;
        self.device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
    }

    pub fn get_system_time_counter(&self) -> DeviceResult<SystemTimeCounter> {
        unimplemented!();
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        unimplemented!();
    }

    /// This function is undocumented in the official, and doesn't seem to be actually in use.
    /// It is still nevertheless included here, if it is used by out-of-tree DVB drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    pub fn set_source(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_ADD_PID as c_ulong, &mut ffi_pid)
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_REMOVE_PID as c_ulong, &mut ffi_pid)
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

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

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use std::path::Path;

use libc::{c_uint,c_ulong};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_pes_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        let mut ffi_size = buffer_size as c_ulong;
        self.device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
    }

    pub fn get_system_time_counter(&self, num: u32) -> DeviceResult<SystemTimeCounter> {
        let mut ffi_stc = ffi::Struct_dmx_stc { num: num as c_uint, base: 0, stc: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_STC as c_ulong, &mut ffi_stc));
        Ok(SystemTimeCounter { base: ffi_stc.base, counter: ffi_stc.stc })
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        unimplemented!();
    }

    /// This function is undocumented in the official, and doesn't seem to be actually in use.
    /// It is still nevertheless included here, if it is used by out-of-tree DVB drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    pub fn set_source(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_ADD_PID as c_ulong, &mut ffi_pid)
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_REMOVE_PID as c_ulong, &mut ffi_pid)
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter {
    pub base: u32,
    pub counter: u64
}
<|endoftext|>