<commit_before>mod attestation_producer;
mod block_producer;
mod config;
mod duties;
pub mod error;
mod service;
mod signer;

use crate::config::{
    Config as ClientConfig, KeySource, DEFAULT_SERVER, DEFAULT_SERVER_GRPC_PORT,
    DEFAULT_SERVER_HTTP_PORT,
};
use crate::service::Service as ValidatorService;
use clap::{App, Arg, ArgMatches, SubCommand};
use eth2_config::Eth2Config;
use lighthouse_bootstrap::Bootstrapper;
use protos::services_grpc::ValidatorServiceClient;
use slog::{crit, error, info, o, Drain, Level, Logger};
use types::{InteropEthSpec, Keypair, MainnetEthSpec, MinimalEthSpec};

pub const DEFAULT_SPEC: &str = "minimal";
pub const DEFAULT_DATA_DIR: &str = ".lighthouse-validator";
pub const CLIENT_CONFIG_FILENAME: &str = "validator-client.toml";
pub const ETH2_CONFIG_FILENAME: &str = "eth2-spec.toml";

type Result<T> = core::result::Result<T, String>;

fn main() {
    // Logging
    let decorator = slog_term::TermDecorator::new().build();
    let decorator = logging::AlignedTermDecorator::new(decorator, logging::MAX_MESSAGE_WIDTH);
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    // CLI
    let matches = App::new("Lighthouse Validator Client")
        .version("0.0.1")
        .author("Sigma Prime <contact@sigmaprime.io>")
        .about("Eth 2.0 Validator Client")
        .arg(
            Arg::with_name("datadir")
                .long("datadir")
                .short("d")
                .value_name("DIR")
                .help("Data directory for keys and databases.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("logfile")
                .long("logfile")
                .value_name("logfile")
                .help("File path where output will be written.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("spec")
                .short("s")
                .long("spec")
                .value_name("TITLE")
                .help("Specifies the default eth2 spec type.")
                .takes_value(true)
                .possible_values(&["mainnet", "minimal", "interop"])
                .conflicts_with("eth2-config")
                .global(true)
        )
        .arg(
            Arg::with_name("eth2-config")
                .long("eth2-config")
                .short("e")
                .value_name("TOML_FILE")
                .help("Path to Ethereum 2.0 config and specification file (e.g., eth2_spec.toml).")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("server")
                .long("server")
                .value_name("NETWORK_ADDRESS")
                .help("Address to connect to BeaconNode.")
                .default_value(DEFAULT_SERVER)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("server-grpc-port")
                .long("g")
                .value_name("PORT")
                .help("Port to use for gRPC API connection to the server.")
                .default_value(DEFAULT_SERVER_GRPC_PORT)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("server-http-port")
                .long("h")
                .value_name("PORT")
                .help("Port to use for HTTP API connection to the server.")
                .default_value(DEFAULT_SERVER_HTTP_PORT)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("debug-level")
                .long("debug-level")
                .value_name("LEVEL")
                .short("s")
                .help("The title of the spec constants for chain config.")
                .takes_value(true)
                .possible_values(&["info", "debug", "trace", "warn", "error", "crit"])
                .default_value("info"),
        )
        /*
         * The "testnet" sub-command.
         *
         * Used for starting testnet validator clients.
         */
        .subcommand(SubCommand::with_name("testnet")
            .about("Starts a testnet validator using INSECURE, predicatable private keys, based off the canonical \
                   validator index. ONLY USE FOR TESTING PURPOSES!")
            .arg(
                Arg::with_name("bootstrap")
                    .short("b")
                    .long("bootstrap")
                    .help("Connect to the RPC server to download the eth2_config via the HTTP API.")
            )
            .subcommand(SubCommand::with_name("insecure")
                .about("Uses the standard, predicatable `interop` keygen method to produce a range \
                        of predicatable private keys and starts performing their validator duties.")
                .arg(Arg::with_name("first_validator")
                    .value_name("VALIDATOR_INDEX")
                    .required(true)
                    .help("The first validator public key to be generated for this client."))
                .arg(Arg::with_name("validator_count")
                    .value_name("COUNT")
                    .required(true)
                    .help("The number of validators."))
            )
        )
        .get_matches();

    let drain = match matches.value_of("debug-level") {
        Some("info") => drain.filter_level(Level::Info),
        Some("debug") => drain.filter_level(Level::Debug),
        Some("trace") => drain.filter_level(Level::Trace),
        Some("warn") => drain.filter_level(Level::Warning),
        Some("error") => drain.filter_level(Level::Error),
        Some("crit") => drain.filter_level(Level::Critical),
        _ => unreachable!("guarded by clap"),
    };
    let log = slog::Logger::root(drain.fuse(), o!());
    let (client_config, eth2_config) = match get_configs(&matches, &log) {
        Ok(tuple) => tuple,
        Err(e) => {
            crit!(
                log,
                "Unable to initialize configuration";
                "error" => e
            );
            return;
        }
    };

    info!(
        log,
        "Starting validator client";
        "datadir" => client_config.full_data_dir().expect("Unable to find datadir").to_str(),
    );

    let result = match eth2_config.spec_constants.as_str() {
        "mainnet" => ValidatorService::<ValidatorServiceClient, Keypair, MainnetEthSpec>::start(
            client_config,
            eth2_config,
            log.clone(),
        ),
        "minimal" => ValidatorService::<ValidatorServiceClient, Keypair, MinimalEthSpec>::start(
            client_config,
            eth2_config,
            log.clone(),
        ),
        "interop" => ValidatorService::<ValidatorServiceClient, Keypair, InteropEthSpec>::start(
            client_config,
            eth2_config,
            log.clone(),
        ),
        other => {
            crit!(log, "Unknown spec constants"; "title" => other);
            return;
        }
    };

    // start the validator service.
    // this specifies the GRPC and signer type to use as the duty manager beacon node.
    match result {
        Ok(_) => info!(log, "Validator client shutdown successfully."),
        Err(e) => crit!(log, "Validator client exited with error"; "error" => e.to_string()),
    }
}

/// Parses the CLI arguments and attempts to load the client and eth2 configuration.
///
/// This is not a pure function, it reads from disk and may contact network servers.
pub fn get_configs(cli_args: &ArgMatches, log: &Logger) -> Result<(ClientConfig, Eth2Config)> {
    let mut client_config = ClientConfig::default();

    if let Some(server) = cli_args.value_of("server") {
        client_config.server = server.to_string();
    }

    if let Some(port) = cli_args.value_of("server-http-port") {
        client_config.server_http_port = port
            .parse::<u16>()
            .map_err(|e| format!("Unable to parse HTTP port: {:?}", e))?;
    }

    if let Some(port) = cli_args.value_of("server-grpc-port") {
        client_config.server_grpc_port = port
            .parse::<u16>()
            .map_err(|e| format!("Unable to parse gRPC port: {:?}", e))?;
    }

    info!(
        log,
        "Beacon node connection info";
        "grpc_port" => client_config.server_grpc_port,
        "http_port" => client_config.server_http_port,
        "server" => &client_config.server,
    );

    match cli_args.subcommand() {
        ("testnet", Some(sub_cli_args)) => {
            if cli_args.is_present("eth2-config") && sub_cli_args.is_present("bootstrap") {
                return Err(
                    "Cannot specify --eth2-config and --bootstrap as it may result \
                     in ambiguity."
                        .into(),
                );
            }
            process_testnet_subcommand(sub_cli_args, client_config, log)
        }
        _ => return Err("You must use the testnet command. See '--help'.".into()),
    }
}

/// Parses the `testnet` CLI subcommand.
///
/// This is not a pure function, it reads from disk and may contact network servers.
fn process_testnet_subcommand(
    cli_args: &ArgMatches,
    mut client_config: ClientConfig,
    log: &Logger,
) -> Result<(ClientConfig, Eth2Config)> {
    let eth2_config = if cli_args.is_present("bootstrap") {
        let bootstrapper = Bootstrapper::from_server_string(format!(
            "http://{}:{}",
            client_config.server, client_config.server_http_port
        ))?;

        let eth2_config = bootstrapper.eth2_config()?;

        info!(
            log,
            "Bootstrapped eth2 config via HTTP";
            "slot_time_millis" => eth2_config.spec.milliseconds_per_slot,
            "spec" => &eth2_config.spec_constants,
        );

        eth2_config
    } else {
        match cli_args.value_of("spec") {
            Some("mainnet") => Eth2Config::mainnet(),
            Some("minimal") => Eth2Config::minimal(),
            Some("interop") => Eth2Config::interop(),
            _ => return Err("No --spec flag provided. See '--help'.".into()),
        }
    };

    client_config.key_source = match cli_args.subcommand() {
        ("insecure", Some(sub_cli_args)) => {
            let first = sub_cli_args
                .value_of("first_validator")
                .ok_or_else(|| "No first validator supplied")?
                .parse::<usize>()
                .map_err(|e| format!("Unable to parse first validator: {:?}", e))?;
            let count = sub_cli_args
                .value_of("validator_count")
                .ok_or_else(|| "No validator count supplied")?
                .parse::<usize>()
                .map_err(|e| format!("Unable to parse validator count: {:?}", e))?;

            info!(
                log,
                "Generating unsafe testing keys";
                "first_validator" => first,
                "count" => count
            );

            KeySource::TestingKeypairRange(first..first + count)
        }
        _ => KeySource::Disk,
    };

    Ok((client_config, eth2_config))
}
<commit_msg>Add extra log to validator client<commit_after>mod attestation_producer;
mod block_producer;
mod config;
mod duties;
pub mod error;
mod service;
mod signer;

use crate::config::{
    Config as ClientConfig, KeySource, DEFAULT_SERVER, DEFAULT_SERVER_GRPC_PORT,
    DEFAULT_SERVER_HTTP_PORT,
};
use crate::service::Service as ValidatorService;
use clap::{App, Arg, ArgMatches, SubCommand};
use eth2_config::Eth2Config;
use lighthouse_bootstrap::Bootstrapper;
use protos::services_grpc::ValidatorServiceClient;
use slog::{crit, error, info, o, Drain, Level, Logger};
use types::{InteropEthSpec, Keypair, MainnetEthSpec, MinimalEthSpec};

pub const DEFAULT_SPEC: &str = "minimal";
pub const DEFAULT_DATA_DIR: &str = ".lighthouse-validator";
pub const CLIENT_CONFIG_FILENAME: &str = "validator-client.toml";
pub const ETH2_CONFIG_FILENAME: &str = "eth2-spec.toml";

type Result<T> = core::result::Result<T, String>;

fn main() {
    // Logging
    let decorator = slog_term::TermDecorator::new().build();
    let decorator = logging::AlignedTermDecorator::new(decorator, logging::MAX_MESSAGE_WIDTH);
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    // CLI
    let matches = App::new("Lighthouse Validator Client")
        .version("0.0.1")
        .author("Sigma Prime <contact@sigmaprime.io>")
        .about("Eth 2.0 Validator Client")
        .arg(
            Arg::with_name("datadir")
                .long("datadir")
                .short("d")
                .value_name("DIR")
                .help("Data directory for keys and databases.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("logfile")
                .long("logfile")
                .value_name("logfile")
                .help("File path where output will be written.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("spec")
                .short("s")
                .long("spec")
                .value_name("TITLE")
                .help("Specifies the default eth2 spec type.")
                .takes_value(true)
                .possible_values(&["mainnet", "minimal", "interop"])
                .conflicts_with("eth2-config")
                .global(true)
        )
        .arg(
            Arg::with_name("eth2-config")
                .long("eth2-config")
                .short("e")
                .value_name("TOML_FILE")
                .help("Path to Ethereum 2.0 config and specification file (e.g., eth2_spec.toml).")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("server")
                .long("server")
                .value_name("NETWORK_ADDRESS")
                .help("Address to connect to BeaconNode.")
                .default_value(DEFAULT_SERVER)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("server-grpc-port")
                .long("g")
                .value_name("PORT")
                .help("Port to use for gRPC API connection to the server.")
                .default_value(DEFAULT_SERVER_GRPC_PORT)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("server-http-port")
                .long("h")
                .value_name("PORT")
                .help("Port to use for HTTP API connection to the server.")
                .default_value(DEFAULT_SERVER_HTTP_PORT)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("debug-level")
                .long("debug-level")
                .value_name("LEVEL")
                .short("s")
                .help("The title of the spec constants for chain config.")
                .takes_value(true)
                .possible_values(&["info", "debug", "trace", "warn", "error", "crit"])
                .default_value("info"),
        )
        /*
         * The "testnet" sub-command.
         *
         * Used for starting testnet validator clients.
         */
        .subcommand(SubCommand::with_name("testnet")
            .about("Starts a testnet validator using INSECURE, predicatable private keys, based off the canonical \
                   validator index. ONLY USE FOR TESTING PURPOSES!")
            .arg(
                Arg::with_name("bootstrap")
                    .short("b")
                    .long("bootstrap")
                    .help("Connect to the RPC server to download the eth2_config via the HTTP API.")
            )
            .subcommand(SubCommand::with_name("insecure")
                .about("Uses the standard, predicatable `interop` keygen method to produce a range \
                        of predicatable private keys and starts performing their validator duties.")
                .arg(Arg::with_name("first_validator")
                    .value_name("VALIDATOR_INDEX")
                    .required(true)
                    .help("The first validator public key to be generated for this client."))
                .arg(Arg::with_name("validator_count")
                    .value_name("COUNT")
                    .required(true)
                    .help("The number of validators."))
            )
        )
        .get_matches();

    let drain = match matches.value_of("debug-level") {
        Some("info") => drain.filter_level(Level::Info),
        Some("debug") => drain.filter_level(Level::Debug),
        Some("trace") => drain.filter_level(Level::Trace),
        Some("warn") => drain.filter_level(Level::Warning),
        Some("error") => drain.filter_level(Level::Error),
        Some("crit") => drain.filter_level(Level::Critical),
        _ => unreachable!("guarded by clap"),
    };
    let log = slog::Logger::root(drain.fuse(), o!());
    let (client_config, eth2_config) = match get_configs(&matches, &log) {
        Ok(tuple) => tuple,
        Err(e) => {
            crit!(
                log,
                "Unable to initialize configuration";
                "error" => e
            );
            return;
        }
    };

    info!(
        log,
        "Starting validator client";
        "datadir" => client_config.full_data_dir().expect("Unable to find datadir").to_str(),
    );

    let result = match eth2_config.spec_constants.as_str() {
        "mainnet" => ValidatorService::<ValidatorServiceClient, Keypair, MainnetEthSpec>::start(
            client_config,
            eth2_config,
            log.clone(),
        ),
        "minimal" => ValidatorService::<ValidatorServiceClient, Keypair, MinimalEthSpec>::start(
            client_config,
            eth2_config,
            log.clone(),
        ),
        "interop" => ValidatorService::<ValidatorServiceClient, Keypair, InteropEthSpec>::start(
            client_config,
            eth2_config,
            log.clone(),
        ),
        other => {
            crit!(log, "Unknown spec constants"; "title" => other);
            return;
        }
    };

    // start the validator service.
    // this specifies the GRPC and signer type to use as the duty manager beacon node.
    match result {
        Ok(_) => info!(log, "Validator client shutdown successfully."),
        Err(e) => crit!(log, "Validator client exited with error"; "error" => e.to_string()),
    }
}

/// Parses the CLI arguments and attempts to load the client and eth2 configuration.
///
/// This is not a pure function, it reads from disk and may contact network servers.
pub fn get_configs(cli_args: &ArgMatches, log: &Logger) -> Result<(ClientConfig, Eth2Config)> {
    let mut client_config = ClientConfig::default();

    if let Some(server) = cli_args.value_of("server") {
        client_config.server = server.to_string();
    }

    if let Some(port) = cli_args.value_of("server-http-port") {
        client_config.server_http_port = port
            .parse::<u16>()
            .map_err(|e| format!("Unable to parse HTTP port: {:?}", e))?;
    }

    if let Some(port) = cli_args.value_of("server-grpc-port") {
        client_config.server_grpc_port = port
            .parse::<u16>()
            .map_err(|e| format!("Unable to parse gRPC port: {:?}", e))?;
    }

    info!(
        log,
        "Beacon node connection info";
        "grpc_port" => client_config.server_grpc_port,
        "http_port" => client_config.server_http_port,
        "server" => &client_config.server,
    );

    match cli_args.subcommand() {
        ("testnet", Some(sub_cli_args)) => {
            if cli_args.is_present("eth2-config") && sub_cli_args.is_present("bootstrap") {
                return Err(
                    "Cannot specify --eth2-config and --bootstrap as it may result \
                     in ambiguity."
                        .into(),
                );
            }
            process_testnet_subcommand(sub_cli_args, client_config, log)
        }
        _ => return Err("You must use the testnet command. See '--help'.".into()),
    }
}

/// Parses the `testnet` CLI subcommand.
///
/// This is not a pure function, it reads from disk and may contact network servers.
fn process_testnet_subcommand(
    cli_args: &ArgMatches,
    mut client_config: ClientConfig,
    log: &Logger,
) -> Result<(ClientConfig, Eth2Config)> {
    let eth2_config = if cli_args.is_present("bootstrap") {
        info!(log, "Connecting to bootstrap server");
        let bootstrapper = Bootstrapper::from_server_string(format!(
            "http://{}:{}",
            client_config.server, client_config.server_http_port
        ))?;

        let eth2_config = bootstrapper.eth2_config()?;

        info!(
            log,
            "Bootstrapped eth2 config via HTTP";
            "slot_time_millis" => eth2_config.spec.milliseconds_per_slot,
            "spec" => &eth2_config.spec_constants,
        );

        eth2_config
    } else {
        match cli_args.value_of("spec") {
            Some("mainnet") => Eth2Config::mainnet(),
            Some("minimal") => Eth2Config::minimal(),
            Some("interop") => Eth2Config::interop(),
            _ => return Err("No --spec flag provided. See '--help'.".into()),
        }
    };

    client_config.key_source = match cli_args.subcommand() {
        ("insecure", Some(sub_cli_args)) => {
            let first = sub_cli_args
                .value_of("first_validator")
                .ok_or_else(|| "No first validator supplied")?
                .parse::<usize>()
                .map_err(|e| format!("Unable to parse first validator: {:?}", e))?;
            let count = sub_cli_args
                .value_of("validator_count")
                .ok_or_else(|| "No validator count supplied")?
                .parse::<usize>()
                .map_err(|e| format!("Unable to parse validator count: {:?}", e))?;

            info!(
                log,
                "Generating unsafe testing keys";
                "first_validator" => first,
                "count" => count
            );

            KeySource::TestingKeypairRange(first..first + count)
        }
        _ => KeySource::Disk,
    };

    Ok((client_config, eth2_config))
}
<|endoftext|>


<commit_before>
// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

//hexadecimal colors aren't numbers
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

//
//use std::heap::{Alloc, System, Layout, AllocErr};
//
//struct MyAllocator;
//
//unsafe impl<'a> Alloc for &'a MyAllocator {
//    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
//        System.alloc(layout)
//    }
//
//    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
//        System.dealloc(ptr, layout)
//    }
//}

use std::alloc::System;

#[global_allocator]
static GLOBAL: System = System;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate rand;
extern crate reqwest;
extern crate hyper_native_tls;
extern crate regex;
extern crate hyper;
extern crate blake2_rfc;
extern crate twox_hash;
extern crate chrono;
extern crate zip;
//extern crate serde;
//extern crate serde_json;
extern crate backtrace;
extern crate num;
extern crate base64;
extern crate sha2;
extern crate unicase;
extern crate app_dirs;
extern crate chashmap;
extern crate parking_lot;
extern crate time;
extern crate uuid;
extern crate lockless;
extern crate smallvec;
#[cfg(test)]
extern crate mockito;

extern crate digest;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate openssl;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate hyper_openssl;

pub mod identifier_styles;
pub mod preludes;
pub mod filesystem;
pub mod fetching;
pub mod caching;
pub mod hashing;
pub mod process_testing;
pub mod process_capture;
pub mod colors;
pub mod debug;
pub mod licensing;
pub mod pollster;
pub mod util;

pub mod timeywimey{
    pub fn time_bucket(seconds_per_bucket: u64, bucket_count: u64) -> u64{
        ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_secs() / seconds_per_bucket % bucket_count
    }
    pub use chrono::prelude::Utc;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

// We'll put our errors in an `errors` module, and other modules in
// this crate will `use errors::*;` to get access to everything
// `error_chain!` creates.
#[allow(unused_doc_comment)]
mod errors {
    // Create the Error, ErrorKind, ResultExt, and Result types

    error_chain! {

        errors{
           LicenseCorrupted(msg: String) {
                description("Please verify/reinstall license; license corrupt.")
                display("Please verify/reinstall license; license corrupt: {}", msg)
           }
           RsaDecryptInputLargerThanModulus
        }

    }
}

#[test]
fn test_file_macro_for_this_build(){
    assert!(file!().starts_with(env!("CARGO_PKG_NAME")))
}

<commit_msg>Renamed lint<commit_after>
// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

//hexadecimal colors aren't numbers
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

//
//use std::heap::{Alloc, System, Layout, AllocErr};
//
//struct MyAllocator;
//
//unsafe impl<'a> Alloc for &'a MyAllocator {
//    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
//        System.alloc(layout)
//    }
//
//    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
//        System.dealloc(ptr, layout)
//    }
//}

use std::alloc::System;

#[global_allocator]
static GLOBAL: System = System;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate rand;
extern crate reqwest;
extern crate hyper_native_tls;
extern crate regex;
extern crate hyper;
extern crate blake2_rfc;
extern crate twox_hash;
extern crate chrono;
extern crate zip;
//extern crate serde;
//extern crate serde_json;
extern crate backtrace;
extern crate num;
extern crate base64;
extern crate sha2;
extern crate unicase;
extern crate app_dirs;
extern crate chashmap;
extern crate parking_lot;
extern crate time;
extern crate uuid;
extern crate lockless;
extern crate smallvec;
#[cfg(test)]
extern crate mockito;

extern crate digest;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate openssl;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate hyper_openssl;

pub mod identifier_styles;
pub mod preludes;
pub mod filesystem;
pub mod fetching;
pub mod caching;
pub mod hashing;
pub mod process_testing;
pub mod process_capture;
pub mod colors;
pub mod debug;
pub mod licensing;
pub mod pollster;
pub mod util;

pub mod timeywimey{
    pub fn time_bucket(seconds_per_bucket: u64, bucket_count: u64) -> u64{
        ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_secs() / seconds_per_bucket % bucket_count
    }
    pub use chrono::prelude::Utc;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

// We'll put our errors in an `errors` module, and other modules in
// this crate will `use errors::*;` to get access to everything
// `error_chain!` creates.
#[allow(unused_doc_comments)]
#[allow(renamed_and_removed_lints)]
mod errors {
    // Create the Error, ErrorKind, ResultExt, and Result types

    error_chain! {

        errors{
           LicenseCorrupted(msg: String) {
                description("Please verify/reinstall license; license corrupt.")
                display("Please verify/reinstall license; license corrupt: {}", msg)
           }
           RsaDecryptInputLargerThanModulus
        }

    }
}

#[test]
fn test_file_macro_for_this_build(){
    assert!(file!().starts_with(env!("CARGO_PKG_NAME")))
}

<|endoftext|>


<commit_before><commit_msg>Delete output file only, if the input and output was opened correctly<commit_after><|endoftext|>


<commit_before><commit_msg>Use vec creation shorthand<commit_after><|endoftext|>


<commit_before><commit_msg>Store buffer as Vec of lines, instead of chars.<commit_after><|endoftext|>


<commit_before><commit_msg>[block] Improve tests<commit_after><|endoftext|>


<commit_before>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use std::process;

use s3::{Client, Config, Region};

use aws_types::region::ProvideRegion;

use structopt::StructOpt;
// use tracing_subscriber::fmt::format::FmtSpan;
// use tracing_subscriber::fmt::SubscriberBuilder;

#[derive(Debug, StructOpt)]
struct Opt {
    /// The default region
    #[structopt(short, long)]
    default_region: Option<String>,

    /// Whether to show all buckets
    #[structopt(short, long)]
    global: bool,

    /// Whether to display additional information
    #[structopt(short, long)]
    verbose: bool,
}

/// Lists your Amazon S3 buckets
/// # Arguments
///
/// * `[-d DEFAULT-REGION]` - The region containing the buckets.
///   If not supplied, uses the value of the **AWS_DEFAULT_REGION** environment variable.
///   If the environment variable is not set, defaults to **us-west-2**.
/// * `[-g]` - Whether to display buckets in all regions.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() {
    let Opt {
        default_region,
        global,
        verbose,
    } = Opt::from_args();

    let region = default_region
        .as_ref()
        .map(|region| Region::new(region.clone()))
        .or_else(|| aws_types::region::default_provider().region())
        .unwrap_or_else(|| Region::new("us-west-2"));

    let r: &str = &region.as_ref();

    if verbose {
        println!("S3 client version: {}", s3::PKG_VERSION);
        println!("Region:            {:?}", &region);

        // SubscriberBuilder::default()
        //    .with_env_filter("info")
        //    .with_span_events(FmtSpan::CLOSE)
        //    .init();
    }

    let config = Config::builder().region(&region).build();

    let client = Client::from_conf(config);

    let mut num_buckets = 0;

    match client.list_buckets().send().await {
        Ok(resp) => {
            println!("\nBuckets:\n");

            let buckets = resp.buckets.unwrap_or_default();

            for bucket in &buckets {
                match &bucket.name {
                    None => {}
                    Some(b) => {
                        if global {
                            println!("{}", b);
                            num_buckets += 1;
                        } else {
                            match client.get_bucket_location().bucket(b).send().await {
                                Ok(resp) => match resp.location_constraint {
                                    None => {
                                        if verbose {
                                            println!("Could not get a location for {}", b);
                                        }
                                    }
                                    Some(c) => {
                                        if verbose {
                                            println!("Location for {}: {}", b, c.as_str());
                                        }
                                        if c.as_str() == r {
                                            println!("{}", b);
                                            num_buckets += 1;
                                        }
                                    }
                                },
                                Err(e) => {
                                    println!("Got an error listing buckets:");
                                    println!("{}", e);
                                    process::exit(1);
                                }
                            };
                        }
                    }
                }
            }

            if global {
                println!("\nFound {} buckets globally", num_buckets);
            } else {
                println!("\nFound {} buckets in {}", num_buckets, r);
            }
        }
        Err(e) => {
            println!("Got an error listing buckets:");
            println!("{}", e);
            process::exit(1);
        }
    };
}
<commit_msg>updated S3 ListBuckets code example for Rust alpha<commit_after>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use std::process;

use s3::{Client, Config, Region};

use aws_types::region::ProvideRegion;

use structopt::StructOpt;
use tracing_subscriber::fmt::format::FmtSpan;
use tracing_subscriber::fmt::SubscriberBuilder;

#[derive(Debug, StructOpt)]
struct Opt {
    /// The default region
    #[structopt(short, long)]
    default_region: Option<String>,

    /// Whether to show all buckets
    #[structopt(short, long)]
    global: bool,

    /// Whether to display additional information
    #[structopt(short, long)]
    verbose: bool,
}

/// Lists your Amazon S3 buckets
/// # Arguments
///
/// * `[-d DEFAULT-REGION]` - The region containing the buckets.
///   If not supplied, uses the value of the **AWS_DEFAULT_REGION** environment variable.
///   If the environment variable is not set, defaults to **us-west-2**.
/// * `[-g]` - Whether to display buckets in all regions.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() {
    let Opt {
        default_region,
        global,
        verbose,
    } = Opt::from_args();

    let region = default_region
        .as_ref()
        .map(|region| Region::new(region.clone()))
        .or_else(|| aws_types::region::default_provider().region())
        .unwrap_or_else(|| Region::new("us-west-2"));

    let r: &str = &region.as_ref();

    if verbose {
        println!("S3 client version: {}", s3::PKG_VERSION);
        println!("Region:            {:?}", &region);

        SubscriberBuilder::default()
            .with_env_filter("info")
            .with_span_events(FmtSpan::CLOSE)
            .init();
    }

    let config = Config::builder().region(&region).build();

    let client = Client::from_conf(config);

    let mut num_buckets = 0;

    match client.list_buckets().send().await {
        Ok(resp) => {
            println!("\nBuckets:\n");

            let buckets = resp.buckets.unwrap_or_default();

            for bucket in &buckets {
                match &bucket.name {
                    None => {}
                    Some(b) => {
                        if global {
                            println!("{}", b);
                            num_buckets += 1;
                        } else {
                            match client.get_bucket_location().bucket(b).send().await {
                                Ok(resp) => match resp.location_constraint {
                                    None => {
                                        if verbose {
                                            println!("Could not get a location for {}", b);
                                        }
                                    }
                                    Some(c) => {
                                        if verbose {
                                            println!("Location for {}: {}", b, c.as_str());
                                        }
                                        if c.as_str() == r {
                                            println!("{}", b);
                                            num_buckets += 1;
                                        }
                                    }
                                },
                                Err(e) => {
                                    println!("Got an error listing buckets:");
                                    println!("{}", e);
                                    process::exit(1);
                                }
                            };
                        }
                    }
                }
            }

            if global {
                println!("\nFound {} buckets globally", num_buckets);
            } else {
                println!("\nFound {} buckets in {}", num_buckets, r);
            }
        }
        Err(e) => {
            println!("Got an error listing buckets:");
            println!("{}", e);
            process::exit(1);
        }
    };
}
<|endoftext|>


<commit_before>use crate::context::Context;
use crate::tera::Tera;

#[test]
fn can_remove_whitespace_basic() {
    let mut context = Context::new();
    context.insert("numbers", &vec![1, 2, 3]);

    let inputs = vec![
        ("  {%- for n in numbers %}{{n}}{% endfor -%} ", "123"),
        ("{%- for n in numbers %} {{n}}{%- endfor -%} ", " 1 2 3"),
        ("{%- for n in numbers -%}\n {{n}}\n {%- endfor -%} ", "123"),
        ("{%- if true -%}\n {{numbers}}\n {%- endif -%} ", "[1, 2, 3]"),
        ("{%- if false -%}\n {{numbers}}\n {% else %} Nope{%- endif -%} ", " Nope"),
        ("  {%- if false -%}\n {{numbers}}\n {% else -%} Nope {%- endif -%} ", "Nope"),
        ("  {%- if false -%}\n {{numbers}}\n {% elif true -%} Nope {%- endif -%} ", "Nope"),
        ("  {%- if false -%}\n {{numbers}}\n {% elif false -%} Nope {% else %} else {%- endif -%} ", " else"),
        ("  {%- set var = 2 -%} {{var}}", "2"),
        ("  {% set var = 2 -%} {{var}}", "  2"),
        ("  {% raw -%}{{2}} {% endraw -%} ", "  {{2}} "),
        ("  {% filter upper -%} hey {%- endfilter -%} ", "  HEY"),
        ("  {{ \"hello\" -}} ", "  hello"),
        ("  {{- \"hello\" }} ", "hello "),
        ("  {{- \"hello\" -}} ", "hello"),
    ];

    for (input, expected) in inputs {
        let mut tera = Tera::default();
        tera.add_raw_template("tpl", input).unwrap();
        assert_eq!(tera.render("tpl", &context).unwrap(), expected);
    }
}

#[test]
fn can_remove_whitespace_include() {
    let mut context = Context::new();
    context.insert("numbers", &vec![1, 2, 3]);

    let inputs = vec![
        (r#"Hi {%- include "include" -%} "#, "HiIncluded"),
        (r#"Hi {% include "include" -%} "#, "Hi Included"),
        (r#"Hi {% include "include" %} "#, "Hi Included "),
    ];

    for (input, expected) in inputs {
        let mut tera = Tera::default();
        tera.add_raw_templates(vec![("include", "Included"), ("tpl", input)]).unwrap();
        assert_eq!(tera.render("tpl", &context).unwrap(), expected);
    }
}

#[test]
fn can_remove_whitespace_macros() {
    let mut context = Context::new();
    context.insert("numbers", &vec![1, 2, 3]);

    let inputs = vec![
        (r#" {%- import "macros" as macros -%} {{macros::hey()}}"#, "Hey!"),
        (r#" {% import "macros" as macros %} {{macros::hey()}}"#, "Hey!"),
        (r#" {%- import "macros" as macros %} {%- set hey = macros::hey() -%} {{hey}}"#, "Hey!"),
    ];

    for (input, expected) in inputs {
        let mut tera = Tera::default();
        tera.add_raw_templates(vec![
            ("macros", "{% macro hey() -%} Hey! {%- endmacro %}"),
            ("tpl", input),
        ])
        .unwrap();
        assert_eq!(tera.render("tpl", &context).unwrap(), expected);
    }
}

#[test]
fn can_remove_whitespace_inheritance() {
    let mut context = Context::new();
    context.insert("numbers", &vec![1, 2, 3]);

    let inputs = vec![
        (r#"{%- extends "base" -%} {% block content %}{{super()}}{% endblock %}"#, " Hey! "),
        (r#"{%- extends "base" -%} {% block content -%}{{super()}}{%- endblock %}"#, " Hey! "),
        (r#"{%- extends "base" %} {%- block content -%}{{super()}}{%- endblock -%} "#, " Hey! "),
    ];

    for (input, expected) in inputs {
        let mut tera = Tera::default();
        tera.add_raw_templates(vec![
            ("base", "{% block content %} Hey! {% endblock %}"),
            ("tpl", input),
        ])
        .unwrap();
        assert_eq!(tera.render("tpl", &context).unwrap(), expected);
    }
}

// https://github.com/Keats/tera/issues/475
#[test]
fn works_with_filter_section() {
    let mut context = Context::new();
    context.insert("d", "d");
    let input = r#"{% filter upper %}  {{ "c" }}   d{% endfilter %}"#;
    let res = Tera::one_off(input, &context, true).unwrap();
    assert_eq!(res, "  C   D");
}
<commit_msg>Update src/renderer/tests/whitespace.rs<commit_after>use crate::context::Context;
use crate::tera::Tera;

#[test]
fn can_remove_whitespace_basic() {
    let mut context = Context::new();
    context.insert("numbers", &vec![1, 2, 3]);

    let inputs = vec![
        ("  {%- for n in numbers %}{{n}}{% endfor -%} ", "123"),
        ("{%- for n in numbers %} {{n}}{%- endfor -%} ", " 1 2 3"),
        ("{%- for n in numbers -%}\n {{n}}\n {%- endfor -%} ", "123"),
        ("{%- if true -%}\n {{numbers}}\n {%- endif -%} ", "[1, 2, 3]"),
        ("{%- if false -%}\n {{numbers}}\n {% else %} Nope{%- endif -%} ", " Nope"),
        ("  {%- if false -%}\n {{numbers}}\n {% else -%} Nope {%- endif -%} ", "Nope"),
        ("  {%- if false -%}\n {{numbers}}\n {% elif true -%} Nope {%- endif -%} ", "Nope"),
        ("  {%- if false -%}\n {{numbers}}\n {% elif false -%} Nope {% else %} else {%- endif -%} ", " else"),
        ("  {%- set var = 2 -%} {{var}}", "2"),
        ("  {% set var = 2 -%} {{var}}", "  2"),
        (" {% raw -%} {{2}} {% endraw -%} ", " {{2}} "),
        ("  {% filter upper -%} hey {%- endfilter -%} ", "  HEY"),
        ("  {{ \"hello\" -}} ", "  hello"),
        ("  {{- \"hello\" }} ", "hello "),
        ("  {{- \"hello\" -}} ", "hello"),
    ];

    for (input, expected) in inputs {
        let mut tera = Tera::default();
        tera.add_raw_template("tpl", input).unwrap();
        assert_eq!(tera.render("tpl", &context).unwrap(), expected);
    }
}

#[test]
fn can_remove_whitespace_include() {
    let mut context = Context::new();
    context.insert("numbers", &vec![1, 2, 3]);

    let inputs = vec![
        (r#"Hi {%- include "include" -%} "#, "HiIncluded"),
        (r#"Hi {% include "include" -%} "#, "Hi Included"),
        (r#"Hi {% include "include" %} "#, "Hi Included "),
    ];

    for (input, expected) in inputs {
        let mut tera = Tera::default();
        tera.add_raw_templates(vec![("include", "Included"), ("tpl", input)]).unwrap();
        assert_eq!(tera.render("tpl", &context).unwrap(), expected);
    }
}

#[test]
fn can_remove_whitespace_macros() {
    let mut context = Context::new();
    context.insert("numbers", &vec![1, 2, 3]);

    let inputs = vec![
        (r#" {%- import "macros" as macros -%} {{macros::hey()}}"#, "Hey!"),
        (r#" {% import "macros" as macros %} {{macros::hey()}}"#, "Hey!"),
        (r#" {%- import "macros" as macros %} {%- set hey = macros::hey() -%} {{hey}}"#, "Hey!"),
    ];

    for (input, expected) in inputs {
        let mut tera = Tera::default();
        tera.add_raw_templates(vec![
            ("macros", "{% macro hey() -%} Hey! {%- endmacro %}"),
            ("tpl", input),
        ])
        .unwrap();
        assert_eq!(tera.render("tpl", &context).unwrap(), expected);
    }
}

#[test]
fn can_remove_whitespace_inheritance() {
    let mut context = Context::new();
    context.insert("numbers", &vec![1, 2, 3]);

    let inputs = vec![
        (r#"{%- extends "base" -%} {% block content %}{{super()}}{% endblock %}"#, " Hey! "),
        (r#"{%- extends "base" -%} {% block content -%}{{super()}}{%- endblock %}"#, " Hey! "),
        (r#"{%- extends "base" %} {%- block content -%}{{super()}}{%- endblock -%} "#, " Hey! "),
    ];

    for (input, expected) in inputs {
        let mut tera = Tera::default();
        tera.add_raw_templates(vec![
            ("base", "{% block content %} Hey! {% endblock %}"),
            ("tpl", input),
        ])
        .unwrap();
        assert_eq!(tera.render("tpl", &context).unwrap(), expected);
    }
}

// https://github.com/Keats/tera/issues/475
#[test]
fn works_with_filter_section() {
    let mut context = Context::new();
    context.insert("d", "d");
    let input = r#"{% filter upper %}  {{ "c" }}   d{% endfilter %}"#;
    let res = Tera::one_off(input, &context, true).unwrap();
    assert_eq!(res, "  C   D");
}
<|endoftext|>


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

use gpu_cache::GpuCacheHandle;
use internal_types::HardwareCompositeOp;
use mask_cache::MaskCacheInfo;
use prim_store::{PrimitiveCacheKey, PrimitiveIndex};
use std::{cmp, f32, i32, mem, usize};
use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex};
use tiling::{RenderTargetKind, StackingContextIndex};
use api::{ClipId, DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{FilterOp, MixBlendMode};

const FLOATS_PER_RENDER_TASK_INFO: usize = 12;

#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub struct RenderTaskIndex(pub usize);

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum RenderTaskKey {
    /// Draw this primitive to a cache target.
    CachePrimitive(PrimitiveCacheKey),
    /// Draw the alpha mask for a primitive.
    CacheMask(MaskCacheKey),
    /// Apply a vertical blur pass of given radius for this primitive.
    VerticalBlur(i32, PrimitiveIndex),
    /// Apply a horizontal blur pass of given radius for this primitive.
    HorizontalBlur(i32, PrimitiveIndex),
    /// Allocate a block of space in target for framebuffer copy.
    CopyFramebuffer(StackingContextIndex),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum MaskCacheKey {
    Primitive(PrimitiveIndex),
    ClipNode(ClipId),
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum RenderTaskId {
    Static(RenderTaskIndex),
    Dynamic(RenderTaskKey),
}

#[derive(Debug, Clone)]
pub enum RenderTaskLocation {
    Fixed,
    Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, DeviceIntSize),
}

#[derive(Debug, Clone)]
pub enum AlphaRenderItem {
    Primitive(Option<ClipScrollGroupIndex>, PrimitiveIndex, i32),
    Blend(StackingContextIndex, RenderTaskId, FilterOp, i32),
    Composite(StackingContextIndex, RenderTaskId, RenderTaskId, MixBlendMode, i32),
    SplitComposite(StackingContextIndex, RenderTaskId, GpuCacheHandle, i32),
    HardwareComposite(StackingContextIndex, RenderTaskId, HardwareCompositeOp, i32),
}

#[derive(Debug, Clone)]
pub struct AlphaRenderTask {
    screen_origin: DeviceIntPoint,
    pub items: Vec<AlphaRenderItem>,
}

#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub enum MaskSegment {
    // This must match the SEGMENT_ values in clip_shared.glsl!
    All = 0,
    TopLeftCorner,
    TopRightCorner,
    BottomLeftCorner,
    BottomRightCorner,
}

#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub enum MaskGeometryKind {
    Default,        // Draw the entire rect
    CornersOnly,    // Draw the corners (simple axis aligned mask)
    // TODO(gw): Add more types here (e.g. 4 rectangles outside the inner rect)
}

pub type ClipWorkItem = (PackedLayerIndex, MaskCacheInfo);

#[derive(Debug, Clone)]
pub struct CacheMaskTask {
    actual_rect: DeviceIntRect,
    inner_rect: DeviceIntRect,
    pub clips: Vec<ClipWorkItem>,
    pub geometry_kind: MaskGeometryKind,
}

#[derive(Debug, Clone)]
pub struct RenderTaskData {
    pub data: [f32; FLOATS_PER_RENDER_TASK_INFO],
}

impl RenderTaskData {
    pub fn empty() -> RenderTaskData {
        RenderTaskData {
            data: unsafe { mem::uninitialized() }
        }
    }
}

impl Default for RenderTaskData {
    fn default() -> RenderTaskData {
        RenderTaskData {
            data: unsafe { mem::uninitialized() },
        }
    }
}

#[derive(Debug, Clone)]
pub enum RenderTaskKind {
    Alpha(AlphaRenderTask),
    CachePrimitive(PrimitiveIndex),
    CacheMask(CacheMaskTask),
    VerticalBlur(DeviceIntLength, PrimitiveIndex),
    HorizontalBlur(DeviceIntLength, PrimitiveIndex),
    Readback(DeviceIntRect),
}

// TODO(gw): Consider storing these in a separate array and having
//           primitives hold indices - this could avoid cloning
//           when adding them as child tasks to tiles.
#[derive(Debug, Clone)]
pub struct RenderTask {
    pub id: RenderTaskId,
    pub location: RenderTaskLocation,
    pub children: Vec<RenderTask>,
    pub kind: RenderTaskKind,
}

impl RenderTask {
    pub fn new_alpha_batch(task_index: RenderTaskIndex,
                           screen_origin: DeviceIntPoint,
                           location: RenderTaskLocation) -> RenderTask {
        RenderTask {
            id: RenderTaskId::Static(task_index),
            children: Vec::new(),
            location,
            kind: RenderTaskKind::Alpha(AlphaRenderTask {
                screen_origin,
                items: Vec::new(),
            }),
        }
    }

    pub fn new_dynamic_alpha_batch(task_index: RenderTaskIndex,
                                   rect: &DeviceIntRect) -> RenderTask {
        let location = RenderTaskLocation::Dynamic(None, rect.size);
        Self::new_alpha_batch(task_index, rect.origin, location)
    }

    pub fn new_prim_cache(key: PrimitiveCacheKey,
                          size: DeviceIntSize,
                          prim_index: PrimitiveIndex) -> RenderTask {
        RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::CachePrimitive(key)),
            children: Vec::new(),
            location: RenderTaskLocation::Dynamic(None, size),
            kind: RenderTaskKind::CachePrimitive(prim_index),
        }
    }

    pub fn new_readback(key: StackingContextIndex,
                    screen_rect: DeviceIntRect) -> RenderTask {
        RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::CopyFramebuffer(key)),
            children: Vec::new(),
            location: RenderTaskLocation::Dynamic(None, screen_rect.size),
            kind: RenderTaskKind::Readback(screen_rect),
        }
    }

    pub fn new_mask(task_rect: DeviceIntRect,
                    mask_key: MaskCacheKey,
                    raw_clips: &[ClipWorkItem],
                    extra_clip: Option<ClipWorkItem>)
                    -> Option<RenderTask> {
        /// Filter out all the clip instances that don't contribute to the result
        let mut inner_rect = Some(task_rect);
        let clips: Vec<_> = raw_clips.iter()
                                     .chain(extra_clip.iter())
                                     .filter(|&&(_, ref clip_info)| {
            match clip_info.bounds.inner {
                Some(ref inner) if !inner.device_rect.is_empty() => {
                    inner_rect = inner_rect.and_then(|r| r.intersection(&inner.device_rect));
                    !inner.device_rect.contains_rect(&task_rect)
                }
                _ => {
                    inner_rect = None;
                    true
                }
            }
        }).cloned().collect();

        // Nothing to do, all clips are irrelevant for this case
        if clips.is_empty() {
            return None
        }

        // TODO(gw): This optimization is very conservative for now.
        //           For now, only draw optimized geometry if it is
        //           a single aligned rect mask with rounded corners.
        //           In the future, we'll expand this to handle the
        //           more complex types of clip mask geometry.
        let mut geometry_kind = MaskGeometryKind::Default;
        if inner_rect.is_some() && clips.len() == 1 {
            let (_, ref info) = clips[0];
            if info.border_corners.is_empty() &&
               info.image.is_none() &&
               info.complex_clip_range.get_count() == 1 &&
               info.layer_clip_range.get_count() == 0 {
                geometry_kind = MaskGeometryKind::CornersOnly;
            }
        }

        Some(RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::CacheMask(mask_key)),
            children: Vec::new(),
            location: RenderTaskLocation::Dynamic(None, task_rect.size),
            kind: RenderTaskKind::CacheMask(CacheMaskTask {
                actual_rect: task_rect,
                inner_rect: inner_rect.unwrap_or(DeviceIntRect::zero()),
                clips,
                geometry_kind,
            }),
        })
    }

    // Construct a render task to apply a blur to a primitive. For now,
    // this is only used for text runs, but we can probably extend this
    // to handle general blurs to any render task in the future.
    // The render task chain that is constructed looks like:
    //
    //    PrimitiveCacheTask: Draw the text run.
    //           ^
    //           |
    //    VerticalBlurTask: Apply the separable vertical blur to the primitive.
    //           ^
    //           |
    //    HorizontalBlurTask: Apply the separable horizontal blur to the vertical blur.
    //           |
    //           +---- This is stored as the input task to the primitive shader.
    //
    pub fn new_blur(key: PrimitiveCacheKey,
                    size: DeviceIntSize,
                    blur_radius: DeviceIntLength,
                    prim_index: PrimitiveIndex) -> RenderTask {
        let prim_cache_task = RenderTask::new_prim_cache(key,
                                                         size,
                                                         prim_index);

        let blur_target_size = size + DeviceIntSize::new(2 * blur_radius.0,
                                                         2 * blur_radius.0);

        let blur_task_v = RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::VerticalBlur(blur_radius.0, prim_index)),
            children: vec![prim_cache_task],
            location: RenderTaskLocation::Dynamic(None, blur_target_size),
            kind: RenderTaskKind::VerticalBlur(blur_radius, prim_index),
        };

        let blur_task_h = RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::HorizontalBlur(blur_radius.0, prim_index)),
            children: vec![blur_task_v],
            location: RenderTaskLocation::Dynamic(None, blur_target_size),
            kind: RenderTaskKind::HorizontalBlur(blur_radius, prim_index),
        };

        blur_task_h
    }

    pub fn as_alpha_batch<'a>(&'a mut self) -> &'a mut AlphaRenderTask {
        match self.kind {
            RenderTaskKind::Alpha(ref mut task) => task,
            RenderTaskKind::CachePrimitive(..) |
            RenderTaskKind::CacheMask(..) |
            RenderTaskKind::VerticalBlur(..) |
            RenderTaskKind::Readback(..) |
            RenderTaskKind::HorizontalBlur(..) => unreachable!(),
        }
    }

    // Write (up to) 8 floats of data specific to the type
    // of render task that is provided to the GPU shaders
    // via a vertex texture.
    pub fn write_task_data(&self) -> RenderTaskData {
        let (target_rect, target_index) = self.get_target_rect();

        // NOTE: The ordering and layout of these structures are
        //       required to match both the GPU structures declared
        //       in prim_shared.glsl, and also the uses in submit_batch()
        //       in renderer.rs.
        // TODO(gw): Maybe there's a way to make this stuff a bit
        //           more type-safe. Although, it will always need
        //           to be kept in sync with the GLSL code anyway.

        match self.kind {
            RenderTaskKind::Alpha(ref task) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        target_rect.size.width as f32,
                        target_rect.size.height as f32,
                        task.screen_origin.x as f32,
                        task.screen_origin.y as f32,
                        target_index.0 as f32,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                    ],
                }
            }
            RenderTaskKind::CachePrimitive(..) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        target_rect.size.width as f32,
                        target_rect.size.height as f32,
                        target_index.0 as f32,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                    ],
                }
            }
            RenderTaskKind::CacheMask(ref task) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        (target_rect.origin.x + target_rect.size.width) as f32,
                        (target_rect.origin.y + target_rect.size.height) as f32,
                        task.actual_rect.origin.x as f32,
                        task.actual_rect.origin.y as f32,
                        target_index.0 as f32,
                        0.0,
                        task.inner_rect.origin.x as f32,
                        task.inner_rect.origin.y as f32,
                        (task.inner_rect.origin.x + task.inner_rect.size.width) as f32,
                        (task.inner_rect.origin.y + task.inner_rect.size.height) as f32,
                    ],
                }
            }
            RenderTaskKind::VerticalBlur(blur_radius, _) |
            RenderTaskKind::HorizontalBlur(blur_radius, _) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        target_rect.size.width as f32,
                        target_rect.size.height as f32,
                        target_index.0 as f32,
                        blur_radius.0 as f32,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                    ]
                }
            }
            RenderTaskKind::Readback(..) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        target_rect.size.width as f32,
                        target_rect.size.height as f32,
                        target_index.0 as f32,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                    ]
                }
            }
        }
    }

    fn get_target_rect(&self) -> (DeviceIntRect, RenderTargetIndex) {
        match self.location {
            RenderTaskLocation::Fixed => {
                (DeviceIntRect::zero(), RenderTargetIndex(0))
            },
            RenderTaskLocation::Dynamic(origin_and_target_index, size) => {
                let (origin, target_index) = origin_and_target_index.expect("Should have been allocated by now!");
                (DeviceIntRect::new(origin, size), target_index)
            }
        }
    }

    pub fn assign_to_passes(mut self, pass_index: usize, passes: &mut Vec<RenderPass>) {
        for child in self.children.drain(..) {
            child.assign_to_passes(pass_index - 1,
                                   passes);
        }

        // Sanity check - can be relaxed if needed
        match self.location {
            RenderTaskLocation::Fixed => {
                debug_assert!(pass_index == passes.len() - 1);
            }
            RenderTaskLocation::Dynamic(..) => {
                debug_assert!(pass_index < passes.len() - 1);
            }
        }

        let pass = &mut passes[pass_index];
        pass.add_render_task(self);
    }

    pub fn max_depth(&self, depth: usize, max_depth: &mut usize) {
        let depth = depth + 1;
        *max_depth = cmp::max(*max_depth, depth);
        for child in &self.children {
            child.max_depth(depth, max_depth);
        }
    }

    pub fn target_kind(&self) -> RenderTargetKind {
        match self.kind {
            RenderTaskKind::Alpha(..) |
            RenderTaskKind::CachePrimitive(..) |
            RenderTaskKind::VerticalBlur(..) |
            RenderTaskKind::Readback(..) |
            RenderTaskKind::HorizontalBlur(..) => RenderTargetKind::Color,
            RenderTaskKind::CacheMask(..) => RenderTargetKind::Alpha,
        }
    }
}
<commit_msg>Change doc comment on statement into regular comment<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gpu_cache::GpuCacheHandle;
use internal_types::HardwareCompositeOp;
use mask_cache::MaskCacheInfo;
use prim_store::{PrimitiveCacheKey, PrimitiveIndex};
use std::{cmp, f32, i32, mem, usize};
use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex};
use tiling::{RenderTargetKind, StackingContextIndex};
use api::{ClipId, DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{FilterOp, MixBlendMode};

const FLOATS_PER_RENDER_TASK_INFO: usize = 12;

#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub struct RenderTaskIndex(pub usize);

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum RenderTaskKey {
    /// Draw this primitive to a cache target.
    CachePrimitive(PrimitiveCacheKey),
    /// Draw the alpha mask for a primitive.
    CacheMask(MaskCacheKey),
    /// Apply a vertical blur pass of given radius for this primitive.
    VerticalBlur(i32, PrimitiveIndex),
    /// Apply a horizontal blur pass of given radius for this primitive.
    HorizontalBlur(i32, PrimitiveIndex),
    /// Allocate a block of space in target for framebuffer copy.
    CopyFramebuffer(StackingContextIndex),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum MaskCacheKey {
    Primitive(PrimitiveIndex),
    ClipNode(ClipId),
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum RenderTaskId {
    Static(RenderTaskIndex),
    Dynamic(RenderTaskKey),
}

#[derive(Debug, Clone)]
pub enum RenderTaskLocation {
    Fixed,
    Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, DeviceIntSize),
}

#[derive(Debug, Clone)]
pub enum AlphaRenderItem {
    Primitive(Option<ClipScrollGroupIndex>, PrimitiveIndex, i32),
    Blend(StackingContextIndex, RenderTaskId, FilterOp, i32),
    Composite(StackingContextIndex, RenderTaskId, RenderTaskId, MixBlendMode, i32),
    SplitComposite(StackingContextIndex, RenderTaskId, GpuCacheHandle, i32),
    HardwareComposite(StackingContextIndex, RenderTaskId, HardwareCompositeOp, i32),
}

#[derive(Debug, Clone)]
pub struct AlphaRenderTask {
    screen_origin: DeviceIntPoint,
    pub items: Vec<AlphaRenderItem>,
}

#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub enum MaskSegment {
    // This must match the SEGMENT_ values in clip_shared.glsl!
    All = 0,
    TopLeftCorner,
    TopRightCorner,
    BottomLeftCorner,
    BottomRightCorner,
}

#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub enum MaskGeometryKind {
    Default,        // Draw the entire rect
    CornersOnly,    // Draw the corners (simple axis aligned mask)
    // TODO(gw): Add more types here (e.g. 4 rectangles outside the inner rect)
}

pub type ClipWorkItem = (PackedLayerIndex, MaskCacheInfo);

#[derive(Debug, Clone)]
pub struct CacheMaskTask {
    actual_rect: DeviceIntRect,
    inner_rect: DeviceIntRect,
    pub clips: Vec<ClipWorkItem>,
    pub geometry_kind: MaskGeometryKind,
}

#[derive(Debug, Clone)]
pub struct RenderTaskData {
    pub data: [f32; FLOATS_PER_RENDER_TASK_INFO],
}

impl RenderTaskData {
    pub fn empty() -> RenderTaskData {
        RenderTaskData {
            data: unsafe { mem::uninitialized() }
        }
    }
}

impl Default for RenderTaskData {
    fn default() -> RenderTaskData {
        RenderTaskData {
            data: unsafe { mem::uninitialized() },
        }
    }
}

#[derive(Debug, Clone)]
pub enum RenderTaskKind {
    Alpha(AlphaRenderTask),
    CachePrimitive(PrimitiveIndex),
    CacheMask(CacheMaskTask),
    VerticalBlur(DeviceIntLength, PrimitiveIndex),
    HorizontalBlur(DeviceIntLength, PrimitiveIndex),
    Readback(DeviceIntRect),
}

// TODO(gw): Consider storing these in a separate array and having
//           primitives hold indices - this could avoid cloning
//           when adding them as child tasks to tiles.
#[derive(Debug, Clone)]
pub struct RenderTask {
    pub id: RenderTaskId,
    pub location: RenderTaskLocation,
    pub children: Vec<RenderTask>,
    pub kind: RenderTaskKind,
}

impl RenderTask {
    pub fn new_alpha_batch(task_index: RenderTaskIndex,
                           screen_origin: DeviceIntPoint,
                           location: RenderTaskLocation) -> RenderTask {
        RenderTask {
            id: RenderTaskId::Static(task_index),
            children: Vec::new(),
            location,
            kind: RenderTaskKind::Alpha(AlphaRenderTask {
                screen_origin,
                items: Vec::new(),
            }),
        }
    }

    pub fn new_dynamic_alpha_batch(task_index: RenderTaskIndex,
                                   rect: &DeviceIntRect) -> RenderTask {
        let location = RenderTaskLocation::Dynamic(None, rect.size);
        Self::new_alpha_batch(task_index, rect.origin, location)
    }

    pub fn new_prim_cache(key: PrimitiveCacheKey,
                          size: DeviceIntSize,
                          prim_index: PrimitiveIndex) -> RenderTask {
        RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::CachePrimitive(key)),
            children: Vec::new(),
            location: RenderTaskLocation::Dynamic(None, size),
            kind: RenderTaskKind::CachePrimitive(prim_index),
        }
    }

    pub fn new_readback(key: StackingContextIndex,
                    screen_rect: DeviceIntRect) -> RenderTask {
        RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::CopyFramebuffer(key)),
            children: Vec::new(),
            location: RenderTaskLocation::Dynamic(None, screen_rect.size),
            kind: RenderTaskKind::Readback(screen_rect),
        }
    }

    pub fn new_mask(task_rect: DeviceIntRect,
                    mask_key: MaskCacheKey,
                    raw_clips: &[ClipWorkItem],
                    extra_clip: Option<ClipWorkItem>)
                    -> Option<RenderTask> {
        // Filter out all the clip instances that don't contribute to the result
        let mut inner_rect = Some(task_rect);
        let clips: Vec<_> = raw_clips.iter()
                                     .chain(extra_clip.iter())
                                     .filter(|&&(_, ref clip_info)| {
            match clip_info.bounds.inner {
                Some(ref inner) if !inner.device_rect.is_empty() => {
                    inner_rect = inner_rect.and_then(|r| r.intersection(&inner.device_rect));
                    !inner.device_rect.contains_rect(&task_rect)
                }
                _ => {
                    inner_rect = None;
                    true
                }
            }
        }).cloned().collect();

        // Nothing to do, all clips are irrelevant for this case
        if clips.is_empty() {
            return None
        }

        // TODO(gw): This optimization is very conservative for now.
        //           For now, only draw optimized geometry if it is
        //           a single aligned rect mask with rounded corners.
        //           In the future, we'll expand this to handle the
        //           more complex types of clip mask geometry.
        let mut geometry_kind = MaskGeometryKind::Default;
        if inner_rect.is_some() && clips.len() == 1 {
            let (_, ref info) = clips[0];
            if info.border_corners.is_empty() &&
               info.image.is_none() &&
               info.complex_clip_range.get_count() == 1 &&
               info.layer_clip_range.get_count() == 0 {
                geometry_kind = MaskGeometryKind::CornersOnly;
            }
        }

        Some(RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::CacheMask(mask_key)),
            children: Vec::new(),
            location: RenderTaskLocation::Dynamic(None, task_rect.size),
            kind: RenderTaskKind::CacheMask(CacheMaskTask {
                actual_rect: task_rect,
                inner_rect: inner_rect.unwrap_or(DeviceIntRect::zero()),
                clips,
                geometry_kind,
            }),
        })
    }

    // Construct a render task to apply a blur to a primitive. For now,
    // this is only used for text runs, but we can probably extend this
    // to handle general blurs to any render task in the future.
    // The render task chain that is constructed looks like:
    //
    //    PrimitiveCacheTask: Draw the text run.
    //           ^
    //           |
    //    VerticalBlurTask: Apply the separable vertical blur to the primitive.
    //           ^
    //           |
    //    HorizontalBlurTask: Apply the separable horizontal blur to the vertical blur.
    //           |
    //           +---- This is stored as the input task to the primitive shader.
    //
    pub fn new_blur(key: PrimitiveCacheKey,
                    size: DeviceIntSize,
                    blur_radius: DeviceIntLength,
                    prim_index: PrimitiveIndex) -> RenderTask {
        let prim_cache_task = RenderTask::new_prim_cache(key,
                                                         size,
                                                         prim_index);

        let blur_target_size = size + DeviceIntSize::new(2 * blur_radius.0,
                                                         2 * blur_radius.0);

        let blur_task_v = RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::VerticalBlur(blur_radius.0, prim_index)),
            children: vec![prim_cache_task],
            location: RenderTaskLocation::Dynamic(None, blur_target_size),
            kind: RenderTaskKind::VerticalBlur(blur_radius, prim_index),
        };

        let blur_task_h = RenderTask {
            id: RenderTaskId::Dynamic(RenderTaskKey::HorizontalBlur(blur_radius.0, prim_index)),
            children: vec![blur_task_v],
            location: RenderTaskLocation::Dynamic(None, blur_target_size),
            kind: RenderTaskKind::HorizontalBlur(blur_radius, prim_index),
        };

        blur_task_h
    }

    pub fn as_alpha_batch<'a>(&'a mut self) -> &'a mut AlphaRenderTask {
        match self.kind {
            RenderTaskKind::Alpha(ref mut task) => task,
            RenderTaskKind::CachePrimitive(..) |
            RenderTaskKind::CacheMask(..) |
            RenderTaskKind::VerticalBlur(..) |
            RenderTaskKind::Readback(..) |
            RenderTaskKind::HorizontalBlur(..) => unreachable!(),
        }
    }

    // Write (up to) 8 floats of data specific to the type
    // of render task that is provided to the GPU shaders
    // via a vertex texture.
    pub fn write_task_data(&self) -> RenderTaskData {
        let (target_rect, target_index) = self.get_target_rect();

        // NOTE: The ordering and layout of these structures are
        //       required to match both the GPU structures declared
        //       in prim_shared.glsl, and also the uses in submit_batch()
        //       in renderer.rs.
        // TODO(gw): Maybe there's a way to make this stuff a bit
        //           more type-safe. Although, it will always need
        //           to be kept in sync with the GLSL code anyway.

        match self.kind {
            RenderTaskKind::Alpha(ref task) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        target_rect.size.width as f32,
                        target_rect.size.height as f32,
                        task.screen_origin.x as f32,
                        task.screen_origin.y as f32,
                        target_index.0 as f32,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                    ],
                }
            }
            RenderTaskKind::CachePrimitive(..) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        target_rect.size.width as f32,
                        target_rect.size.height as f32,
                        target_index.0 as f32,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                    ],
                }
            }
            RenderTaskKind::CacheMask(ref task) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        (target_rect.origin.x + target_rect.size.width) as f32,
                        (target_rect.origin.y + target_rect.size.height) as f32,
                        task.actual_rect.origin.x as f32,
                        task.actual_rect.origin.y as f32,
                        target_index.0 as f32,
                        0.0,
                        task.inner_rect.origin.x as f32,
                        task.inner_rect.origin.y as f32,
                        (task.inner_rect.origin.x + task.inner_rect.size.width) as f32,
                        (task.inner_rect.origin.y + task.inner_rect.size.height) as f32,
                    ],
                }
            }
            RenderTaskKind::VerticalBlur(blur_radius, _) |
            RenderTaskKind::HorizontalBlur(blur_radius, _) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        target_rect.size.width as f32,
                        target_rect.size.height as f32,
                        target_index.0 as f32,
                        blur_radius.0 as f32,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                    ]
                }
            }
            RenderTaskKind::Readback(..) => {
                RenderTaskData {
                    data: [
                        target_rect.origin.x as f32,
                        target_rect.origin.y as f32,
                        target_rect.size.width as f32,
                        target_rect.size.height as f32,
                        target_index.0 as f32,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                    ]
                }
            }
        }
    }

    fn get_target_rect(&self) -> (DeviceIntRect, RenderTargetIndex) {
        match self.location {
            RenderTaskLocation::Fixed => {
                (DeviceIntRect::zero(), RenderTargetIndex(0))
            },
            RenderTaskLocation::Dynamic(origin_and_target_index, size) => {
                let (origin, target_index) = origin_and_target_index.expect("Should have been allocated by now!");
                (DeviceIntRect::new(origin, size), target_index)
            }
        }
    }

    pub fn assign_to_passes(mut self, pass_index: usize, passes: &mut Vec<RenderPass>) {
        for child in self.children.drain(..) {
            child.assign_to_passes(pass_index - 1,
                                   passes);
        }

        // Sanity check - can be relaxed if needed
        match self.location {
            RenderTaskLocation::Fixed => {
                debug_assert!(pass_index == passes.len() - 1);
            }
            RenderTaskLocation::Dynamic(..) => {
                debug_assert!(pass_index < passes.len() - 1);
            }
        }

        let pass = &mut passes[pass_index];
        pass.add_render_task(self);
    }

    pub fn max_depth(&self, depth: usize, max_depth: &mut usize) {
        let depth = depth + 1;
        *max_depth = cmp::max(*max_depth, depth);
        for child in &self.children {
            child.max_depth(depth, max_depth);
        }
    }

    pub fn target_kind(&self) -> RenderTargetKind {
        match self.kind {
            RenderTaskKind::Alpha(..) |
            RenderTaskKind::CachePrimitive(..) |
            RenderTaskKind::VerticalBlur(..) |
            RenderTaskKind::Readback(..) |
            RenderTaskKind::HorizontalBlur(..) => RenderTargetKind::Color,
            RenderTaskKind::CacheMask(..) => RenderTargetKind::Alpha,
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2015 Y. T. Chung

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use std::io::{self, Read, BufRead, Write};
use std::cmp;
use std::mem;

use crypto::{Cipher, CipherVariant};

use futures::{Future, Poll};

/// Reader wrapper that will decrypt data automatically
pub struct DecryptedReader<R>
    where R: Read
{
    reader: R,
    buffer: Vec<u8>,
    cipher: CipherVariant,
    pos: usize,
    sent_final: bool,
}

const BUFFER_SIZE: usize = 2048;

impl<R> DecryptedReader<R>
    where R: Read
{
    pub fn new(r: R, cipher: CipherVariant) -> DecryptedReader<R> {
        DecryptedReader {
            reader: r,
            buffer: Vec::new(),
            cipher: cipher,
            pos: 0,
            sent_final: false,
        }
    }

    pub fn get_ref(&self) -> &R {
        &self.reader
    }

    /// Gets a mutable reference to the underlying reader.
    ///
    /// # Warning
    ///
    /// It is inadvisable to read directly from or write directly to the
    /// underlying reader.
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.reader
    }

    /// Unwraps this `DecryptedReader`, returning the underlying reader.
    ///
    /// The internal buffer is flushed before returning the reader. Any leftover
    /// data in the read buffer is lost.
    pub fn into_inner(self) -> R {
        self.reader
    }
}

impl<R> BufRead for DecryptedReader<R>
    where R: Read
{
    fn fill_buf<'b>(&'b mut self) -> io::Result<&'b [u8]> {
        while self.pos >= self.buffer.len() {
            if self.sent_final {
                return Ok(&[]);
            }

            let mut incoming = [0u8; BUFFER_SIZE];
            self.buffer.clear();
            match self.reader.read(&mut incoming) {
                Ok(0) => {
                    // EOF
                    try!(self.cipher
                        .finalize(&mut self.buffer));
                    self.sent_final = true;
                }
                Ok(l) => {
                    try!(self.cipher
                        .update(&incoming[..l], &mut self.buffer));
                }
                Err(err) => {
                    return Err(err);
                }
            }

            self.pos = 0;
        }

        Ok(&self.buffer[self.pos..])
    }

    fn consume(&mut self, amt: usize) {
        self.pos = cmp::min(self.pos + amt, self.buffer.len());
    }
}

impl<R> Read for DecryptedReader<R>
    where R: Read
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let nread = {
            let mut available = try!(self.fill_buf());
            try!(available.read(buf))
        };
        self.consume(nread);
        Ok(nread)
    }
}

/// Writer wrapper that will encrypt data automatically
pub struct EncryptedWriter<W>
    where W: Write
{
    writer: W,
    cipher: CipherVariant,
}

impl<W> EncryptedWriter<W>
    where W: Write
{
    /// Creates a new EncryptedWriter
    pub fn new(w: W, cipher: CipherVariant) -> EncryptedWriter<W> {
        EncryptedWriter {
            writer: w,
            cipher: cipher,
        }
    }

    /// Get reference to the inner writer
    pub fn get_ref(&self) -> &W {
        &self.writer
    }

    /// Gets a mutable reference to the underlying writer.
    ///
    /// # Warning
    ///
    /// It is inadvisable to read directly from or write directly to the
    /// underlying writer.
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }

    fn cipher_update(&mut self, buf: &[u8], out: &mut Vec<u8>) -> io::Result<()> {
        self.cipher.update(buf, out).map_err(From::from)
    }

    fn cipher_finalize(&mut self, out: &mut Vec<u8>) -> io::Result<()> {
        self.cipher.finalize(out).map_err(From::from)
    }

    /// write_all
    pub fn write_all<B: AsRef<[u8]>>(self, buf: B) -> EncryptedWriteAll<W, B> {
        EncryptedWriteAll::Writing {
            writer: self,
            buf: buf,
            pos: 0,
            enc_buf: Vec::new(),
            encrypted: false,
        }
    }

    /// Copy all data from reader
    pub fn copy_from<R: Read>(self, r: R) -> EncryptedCopy<R, W> {
        EncryptedCopy {
            reader: r,
            writer: self,
            read_done: false,
            amt: 0,
            pos: 0,
            cap: 0,
            buf: Vec::new(),
        }
    }
}

impl<W> Write for EncryptedWriter<W>
    where W: Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.writer.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

/// write_all and encrypt data
pub enum EncryptedWriteAll<W, B>
    where W: Write,
          B: AsRef<[u8]>
{
    Writing {
        writer: EncryptedWriter<W>,
        buf: B,
        pos: usize,
        enc_buf: Vec<u8>,
        encrypted: bool,
    },
    Empty,
}

impl<W, B> Future for EncryptedWriteAll<W, B>
    where W: Write,
          B: AsRef<[u8]>
{
    type Item = (EncryptedWriter<W>, B);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match *self {
            EncryptedWriteAll::Empty => panic!("poll after EncryptedWriteAll finished"),
            EncryptedWriteAll::Writing { ref mut writer, ref buf, ref mut pos, ref mut enc_buf, ref mut encrypted } => {
                if !*encrypted {
                    *encrypted = true;
                    try!(writer.cipher_update(buf.as_ref(), enc_buf));
                }

                while *pos < enc_buf.len() {
                    let n = try_nb!(writer.write(&enc_buf[*pos..]));
                    *pos += n;
                    if n == 0 {
                        let err = io::Error::new(io::ErrorKind::Other, "zero-length write");
                        return Err(err);
                    }
                }
            }
        }

        match mem::replace(self, EncryptedWriteAll::Empty) {
            EncryptedWriteAll::Writing { writer, buf, .. } => Ok((writer, buf).into()),
            EncryptedWriteAll::Empty => unreachable!(),
        }
    }
}

/// Encrypted copy
pub struct EncryptedCopy<R: Read, W: Write> {
    reader: R,
    writer: EncryptedWriter<W>,
    read_done: bool,
    amt: u64,
    pos: usize,
    cap: usize,
    buf: Vec<u8>,
}

impl<R: Read, W: Write> Future for EncryptedCopy<R, W> {
    type Item = u64;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut local_buf = [0u8; 2048];
        loop {
            // If our buffer is empty, then we need to read some data to
            // continue.
            if self.pos == self.cap && !self.read_done {
                let n = try_nb!(self.reader.read(&mut local_buf[..]));
                if n == 0 {
                    self.read_done = true;
                } else {
                    self.pos = 0;

                    self.buf.clear();
                    try!(self.writer.cipher_update(&local_buf[..n], &mut self.buf));
                    self.cap = self.buf.len();
                }
            }

            // If our buffer has some data, let's write it out!
            while self.pos < self.cap {
                let i = try_nb!(self.writer.write(&self.buf[self.pos..self.cap]));
                self.pos += i;
                self.amt += i as u64;
            }

            // If we've written al the data and we've seen EOF, flush out the
            // data and finish the transfer.
            // done with the entire transfer.
            if self.pos == self.cap && self.read_done {
                try_nb!(self.writer.flush());
                return Ok(self.amt.into());
            }
        }
    }
}<commit_msg>add finalize after read done<commit_after>// The MIT License (MIT)

// Copyright (c) 2015 Y. T. Chung

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use std::io::{self, Read, BufRead, Write};
use std::cmp;
use std::mem;

use crypto::{Cipher, CipherVariant};

use futures::{Future, Poll};

/// Reader wrapper that will decrypt data automatically
pub struct DecryptedReader<R>
    where R: Read
{
    reader: R,
    buffer: Vec<u8>,
    cipher: CipherVariant,
    pos: usize,
    sent_final: bool,
}

const BUFFER_SIZE: usize = 2048;

impl<R> DecryptedReader<R>
    where R: Read
{
    pub fn new(r: R, cipher: CipherVariant) -> DecryptedReader<R> {
        DecryptedReader {
            reader: r,
            buffer: Vec::new(),
            cipher: cipher,
            pos: 0,
            sent_final: false,
        }
    }

    pub fn get_ref(&self) -> &R {
        &self.reader
    }

    /// Gets a mutable reference to the underlying reader.
    ///
    /// # Warning
    ///
    /// It is inadvisable to read directly from or write directly to the
    /// underlying reader.
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.reader
    }

    /// Unwraps this `DecryptedReader`, returning the underlying reader.
    ///
    /// The internal buffer is flushed before returning the reader. Any leftover
    /// data in the read buffer is lost.
    pub fn into_inner(self) -> R {
        self.reader
    }
}

impl<R> BufRead for DecryptedReader<R>
    where R: Read
{
    fn fill_buf<'b>(&'b mut self) -> io::Result<&'b [u8]> {
        while self.pos >= self.buffer.len() {
            if self.sent_final {
                return Ok(&[]);
            }

            let mut incoming = [0u8; BUFFER_SIZE];
            self.buffer.clear();
            match self.reader.read(&mut incoming) {
                Ok(0) => {
                    // EOF
                    try!(self.cipher
                        .finalize(&mut self.buffer));
                    self.sent_final = true;
                }
                Ok(l) => {
                    try!(self.cipher
                        .update(&incoming[..l], &mut self.buffer));
                }
                Err(err) => {
                    return Err(err);
                }
            }

            self.pos = 0;
        }

        Ok(&self.buffer[self.pos..])
    }

    fn consume(&mut self, amt: usize) {
        self.pos = cmp::min(self.pos + amt, self.buffer.len());
    }
}

impl<R> Read for DecryptedReader<R>
    where R: Read
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let nread = {
            let mut available = try!(self.fill_buf());
            try!(available.read(buf))
        };
        self.consume(nread);
        Ok(nread)
    }
}

/// Writer wrapper that will encrypt data automatically
pub struct EncryptedWriter<W>
    where W: Write
{
    writer: W,
    cipher: CipherVariant,
}

impl<W> EncryptedWriter<W>
    where W: Write
{
    /// Creates a new EncryptedWriter
    pub fn new(w: W, cipher: CipherVariant) -> EncryptedWriter<W> {
        EncryptedWriter {
            writer: w,
            cipher: cipher,
        }
    }

    /// Get reference to the inner writer
    pub fn get_ref(&self) -> &W {
        &self.writer
    }

    /// Gets a mutable reference to the underlying writer.
    ///
    /// # Warning
    ///
    /// It is inadvisable to read directly from or write directly to the
    /// underlying writer.
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }

    fn cipher_update(&mut self, buf: &[u8], out: &mut Vec<u8>) -> io::Result<()> {
        self.cipher.update(buf, out).map_err(From::from)
    }

    fn cipher_finalize(&mut self, out: &mut Vec<u8>) -> io::Result<()> {
        self.cipher.finalize(out).map_err(From::from)
    }

    /// write_all
    pub fn write_all<B: AsRef<[u8]>>(self, buf: B) -> EncryptedWriteAll<W, B> {
        EncryptedWriteAll::Writing {
            writer: self,
            buf: buf,
            pos: 0,
            enc_buf: Vec::new(),
            encrypted: false,
        }
    }

    /// Copy all data from reader
    pub fn copy_from<R: Read>(self, r: R) -> EncryptedCopy<R, W> {
        EncryptedCopy {
            reader: r,
            writer: self,
            read_done: false,
            amt: 0,
            pos: 0,
            cap: 0,
            buf: Vec::new(),
        }
    }
}

impl<W> Write for EncryptedWriter<W>
    where W: Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.writer.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

/// write_all and encrypt data
pub enum EncryptedWriteAll<W, B>
    where W: Write,
          B: AsRef<[u8]>
{
    Writing {
        writer: EncryptedWriter<W>,
        buf: B,
        pos: usize,
        enc_buf: Vec<u8>,
        encrypted: bool,
    },
    Empty,
}

impl<W, B> Future for EncryptedWriteAll<W, B>
    where W: Write,
          B: AsRef<[u8]>
{
    type Item = (EncryptedWriter<W>, B);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match *self {
            EncryptedWriteAll::Empty => panic!("poll after EncryptedWriteAll finished"),
            EncryptedWriteAll::Writing { ref mut writer, ref buf, ref mut pos, ref mut enc_buf, ref mut encrypted } => {
                if !*encrypted {
                    *encrypted = true;
                    try!(writer.cipher_update(buf.as_ref(), enc_buf));
                }

                while *pos < enc_buf.len() {
                    let n = try_nb!(writer.write(&enc_buf[*pos..]));
                    *pos += n;
                    if n == 0 {
                        let err = io::Error::new(io::ErrorKind::Other, "zero-length write");
                        return Err(err);
                    }
                }
            }
        }

        match mem::replace(self, EncryptedWriteAll::Empty) {
            EncryptedWriteAll::Writing { writer, buf, .. } => Ok((writer, buf).into()),
            EncryptedWriteAll::Empty => unreachable!(),
        }
    }
}

/// Encrypted copy
pub struct EncryptedCopy<R: Read, W: Write> {
    reader: R,
    writer: EncryptedWriter<W>,
    read_done: bool,
    amt: u64,
    pos: usize,
    cap: usize,
    buf: Vec<u8>,
}

impl<R: Read, W: Write> Future for EncryptedCopy<R, W> {
    type Item = u64;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut local_buf = [0u8; 2048];
        loop {
            // If our buffer is empty, then we need to read some data to
            // continue.
            if self.pos == self.cap && !self.read_done {
                let n = try_nb!(self.reader.read(&mut local_buf[..]));
                self.buf.clear();
                if n == 0 {
                    self.read_done = true;
                    try!(self.writer.cipher_finalize(&mut self.buf));
                } else {
                    try!(self.writer.cipher_update(&local_buf[..n], &mut self.buf));
                }
                self.pos = 0;
                self.cap = self.buf.len();
            }

            // If our buffer has some data, let's write it out!
            while self.pos < self.cap {
                let i = try_nb!(self.writer.write(&self.buf[self.pos..self.cap]));
                self.pos += i;
                self.amt += i as u64;
            }

            // If we've written al the data and we've seen EOF, flush out the
            // data and finish the transfer.
            // done with the entire transfer.
            if self.pos == self.cap && self.read_done {
                try_nb!(self.writer.flush());
                return Ok(self.amt.into());
            }
        }
    }
}<|endoftext|>


<commit_before><commit_msg>Fix a warning with appending values to the graphics array<commit_after><|endoftext|>