<commit_before>// Copyright 2017 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::single_match_else,
  clippy::unseparated_literal_suffix,
  clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(
  clippy::new_without_default,
  clippy::new_without_default_derive,
  clippy::new_ret_no_self
)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

use clap;
use env_logger;
use fs;

use process_execution;

use clap::{value_t, App, AppSettings, Arg};
use futures::future::Future;
use hashing::{Digest, Fingerprint};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::Iterator;
use std::path::PathBuf;
use std::process::exit;
use std::sync::Arc;
use std::time::Duration;

/// A binary which takes args of format:
///  process_executor --env=FOO=bar --env=SOME=value --input-digest=abc123 --input-digest-length=80
///    -- /path/to/binary --flag --otherflag
/// and runs /path/to/binary --flag --otherflag with FOO and SOME set.
/// It outputs its output/err to stdout/err, and exits with its exit code.
///
/// It does not perform $PATH lookup or shell expansion.
fn main() {
  env_logger::init();

  let args = App::new("process_executor")
    .arg(
      Arg::with_name("work-dir")
        .long("work-dir")
        .takes_value(true)
        .help("Path to workdir"),
    )
    .arg(
      Arg::with_name("local-store-path")
        .long("local-store-path")
        .takes_value(true)
        .help("Path to lmdb directory used for local file storage"),
    )
    .arg(
      Arg::with_name("input-digest")
        .long("input-digest")
        .takes_value(true)
        .required(true)
        .help("Fingerprint (hex string) of the digest to use as the input file tree."),
    )
    .arg(
      Arg::with_name("input-digest-length")
        .long("input-digest-length")
        .takes_value(true)
        .required(true)
        .help("Length of the proto-bytes whose digest to use as the input file tree."),
    )
    .arg(
      Arg::with_name("server")
        .long("server")
        .takes_value(true)
        .help(
          "The host:port of the gRPC server to connect to. Forces remote execution. \
           If unspecified, local execution will be performed.",
        ),
    )
      .arg(
        Arg::with_name("execution-oauth-bearer-token-path")
            .help("Path to file containing oauth bearer token for communication with the execution server. If not set, no authorization will be provided to remote servers.")
            .takes_value(true)
            .long("execution-oauth-bearer-token-path")
            .required(false)
      )
      .arg(
      Arg::with_name("cas-server")
        .long("cas-server")
        .takes_value(true)
        .help("The host:port of the gRPC CAS server to connect to."),
    )
      .arg(
        Arg::with_name("cas-root-ca-cert-file")
            .help("Path to file containing root certificate authority certificates for the CAS server. If not set, TLS will not be used when connecting to the CAS server.")
            .takes_value(true)
            .long("cas-root-ca-cert-file")
            .required(false)
      )
      .arg(
        Arg::with_name("cas-oauth-bearer-token-path")
            .help("Path to file containing oauth bearer token for communication with the CAS server. If not set, no authorization will be provided to remote servers.")
            .takes_value(true)
            .long("cas-oauth-bearer-token-path")
            .required(false)
      )
      .arg(Arg::with_name("remote-instance-name")
          .takes_value(true)
          .long("remote-instance-name")
          .required(false))
      .arg(Arg::with_name("cache-key-gen-version")
          .takes_value(true)
          .long("cache-key-gen-version")
          .required(false))
      .arg(
        Arg::with_name("upload-chunk-bytes")
            .help("Number of bytes to include per-chunk when uploading bytes. grpc imposes a hard message-size limit of around 4MB.")
            .takes_value(true)
            .long("chunk-bytes")
            .required(false)
            .default_value("3145728") // 3MB
      )
    .arg(
      Arg::with_name("env")
        .long("env")
        .takes_value(true)
        .multiple(true)
        .help("Environment variables with which the process should be run."),
    )
      .arg(
        Arg::with_name("jdk")
            .long("jdk")
            .takes_value(true)
            .required(false)
            .help("Symlink a JDK from .jdk in the working directory. For local execution, symlinks to the value of this flag. For remote execution, just requests that some JDK is symlinked if this flag has any value. https://github.com/pantsbuild/pants/issues/6416 will make this less weird in the future.")
      )
    .setting(AppSettings::TrailingVarArg)
    .arg(
      Arg::with_name("argv")
        .multiple(true)
        .last(true)
        .required(true),
    )
    .get_matches();

  let argv: Vec<String> = args
    .values_of("argv")
    .unwrap()
    .map(|v| v.to_string())
    .collect();
  let env: BTreeMap<String, String> = match args.values_of("env") {
    Some(values) => values
      .map(|v| {
        let mut parts = v.splitn(2, '=');
        (
          parts.next().unwrap().to_string(),
          parts.next().unwrap_or_default().to_string(),
        )
      })
      .collect(),
    None => BTreeMap::new(),
  };
  let work_dir = args
    .value_of("work-dir")
    .map(PathBuf::from)
    .unwrap_or_else(std::env::temp_dir);
  let local_store_path = args
    .value_of("local-store-path")
    .map(PathBuf::from)
    .unwrap_or_else(fs::Store::default_path);
  let pool = Arc::new(fs::ResettablePool::new("process-executor-".to_owned()));
  let timer_thread = resettable::Resettable::new(|| futures_timer::HelperThread::new().unwrap());
  let server_arg = args.value_of("server");
  let remote_instance_arg = args.value_of("remote-instance-name").map(str::to_owned);

  let store = match (server_arg, args.value_of("cas-server")) {
    (Some(_server), Some(cas_server)) => {
      let chunk_size =
        value_t!(args.value_of("upload-chunk-bytes"), usize).expect("Bad upload-chunk-bytes flag");

      let root_ca_certs = if let Some(path) = args.value_of("cas-root-ca-cert-file") {
        Some(std::fs::read(path).expect("Error reading root CA certs file"))
      } else {
        None
      };

      let oauth_bearer_token = if let Some(path) = args.value_of("cas-oauth-bearer-token-path") {
        Some(std::fs::read_to_string(path).expect("Error reading oauth bearer token file"))
      } else {
        None
      };

      fs::Store::with_remote(
        local_store_path,
        pool.clone(),
        &[cas_server.to_owned()],
        remote_instance_arg.clone(),
        &root_ca_certs,
        oauth_bearer_token,
        1,
        chunk_size,
        Duration::from_secs(30),
        // TODO: Take a command line arg.
        fs::BackoffConfig::new(Duration::from_secs(1), 1.2, Duration::from_secs(20)).unwrap(),
        3,
        timer_thread.with(|t| t.handle()),
      )
    }
    (None, None) => fs::Store::local_only(local_store_path, pool.clone()),
    _ => panic!("Must specify either both --server and --cas-server or neither."),
  }
  .expect("Error making store");

  let input_files = {
    let fingerprint = Fingerprint::from_hex_string(args.value_of("input-digest").unwrap())
      .expect("Bad input-digest");
    let length = args
      .value_of("input-digest-length")
      .unwrap()
      .parse::<usize>()
      .expect("input-digest-length must be a non-negative number");
    Digest(fingerprint, length)
  };

  let request = process_execution::ExecuteProcessRequest {
    argv,
    env,
    input_files,
    output_files: BTreeSet::new(),
    output_directories: BTreeSet::new(),
    timeout: Duration::new(15 * 60, 0),
    description: "process_executor".to_string(),
    jdk_home: args.value_of("jdk").map(PathBuf::from),
  };

  let runner: Box<dyn process_execution::CommandRunner> = match server_arg {
    Some(address) => {
      let oauth_bearer_token =
        if let Some(path) = args.value_of("execution-oauth-bearer-token-path") {
          Some(std::fs::read_to_string(path).expect("Error reading oauth bearer token file"))
        } else {
          None
        };

      Box::new(
        process_execution::remote::CommandRunner::new(
          address,
          args.value_of("cache-key-gen-version").map(str::to_owned),
          remote_instance_arg,
          oauth_bearer_token,
          store,
          timer_thread,
        )
        .expect("Could not initialize remote execution client"),
      ) as Box<dyn process_execution::CommandRunner>
    }
    None => Box::new(process_execution::local::CommandRunner::new(
      store, pool, work_dir, true,
    )) as Box<dyn process_execution::CommandRunner>,
  };
  let mut rt = tokio::runtime::Runtime::new().unwrap();
  let result = rt.block_on(runner.run(request)).unwrap();

  print!("{}", String::from_utf8(result.stdout.to_vec()).unwrap());
  eprint!("{}", String::from_utf8(result.stderr.to_vec()).unwrap());

  rt.shutdown_now().wait().unwrap();

  exit(result.exit_code);
}
<commit_msg>Add flags to prosecc_executor that say where to materialize output and what is output  (#7201)<commit_after>// Copyright 2017 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::single_match_else,
  clippy::unseparated_literal_suffix,
  clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(
  clippy::new_without_default,
  clippy::new_without_default_derive,
  clippy::new_ret_no_self
)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

use clap;
use env_logger;
use fs;

use process_execution;

use clap::{value_t, App, AppSettings, Arg};
use futures::future::Future;
use hashing::{Digest, Fingerprint};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::Iterator;
use std::path::PathBuf;
use std::process::exit;
use std::sync::Arc;
use std::time::Duration;

/// A binary which takes args of format:
///  process_executor --env=FOO=bar --env=SOME=value --input-digest=abc123 --input-digest-length=80
///    -- /path/to/binary --flag --otherflag
/// and runs /path/to/binary --flag --otherflag with FOO and SOME set.
/// It outputs its output/err to stdout/err, and exits with its exit code.
///
/// It does not perform $PATH lookup or shell expansion.
fn main() {
  env_logger::init();

  let args = App::new("process_executor")
    .arg(
      Arg::with_name("work-dir")
        .long("work-dir")
        .takes_value(true)
        .help("Path to workdir"),
    )
    .arg(
      Arg::with_name("local-store-path")
        .long("local-store-path")
        .takes_value(true)
        .help("Path to lmdb directory used for local file storage"),
    )
    .arg(
      Arg::with_name("input-digest")
        .long("input-digest")
        .takes_value(true)
        .required(true)
        .help("Fingerprint (hex string) of the digest to use as the input file tree."),
    )
    .arg(
      Arg::with_name("input-digest-length")
        .long("input-digest-length")
        .takes_value(true)
        .required(true)
        .help("Length of the proto-bytes whose digest to use as the input file tree."),
    )
    .arg(
      Arg::with_name("server")
        .long("server")
        .takes_value(true)
        .help(
          "The host:port of the gRPC server to connect to. Forces remote execution. \
           If unspecified, local execution will be performed.",
        ),
    )
      .arg(
        Arg::with_name("execution-oauth-bearer-token-path")
            .help("Path to file containing oauth bearer token for communication with the execution server. If not set, no authorization will be provided to remote servers.")
            .takes_value(true)
            .long("execution-oauth-bearer-token-path")
            .required(false)
      )
      .arg(
      Arg::with_name("cas-server")
        .long("cas-server")
        .takes_value(true)
        .help("The host:port of the gRPC CAS server to connect to."),
    )
      .arg(
        Arg::with_name("cas-root-ca-cert-file")
            .help("Path to file containing root certificate authority certificates for the CAS server. If not set, TLS will not be used when connecting to the CAS server.")
            .takes_value(true)
            .long("cas-root-ca-cert-file")
            .required(false)
      )
      .arg(
        Arg::with_name("cas-oauth-bearer-token-path")
            .help("Path to file containing oauth bearer token for communication with the CAS server. If not set, no authorization will be provided to remote servers.")
            .takes_value(true)
            .long("cas-oauth-bearer-token-path")
            .required(false)
      )
      .arg(Arg::with_name("remote-instance-name")
          .takes_value(true)
          .long("remote-instance-name")
          .required(false))
      .arg(Arg::with_name("cache-key-gen-version")
          .takes_value(true)
          .long("cache-key-gen-version")
          .required(false))
      .arg(
        Arg::with_name("upload-chunk-bytes")
            .help("Number of bytes to include per-chunk when uploading bytes. grpc imposes a hard message-size limit of around 4MB.")
            .takes_value(true)
            .long("chunk-bytes")
            .required(false)
            .default_value("3145728") // 3MB
      )
    .arg(
      Arg::with_name("env")
        .long("env")
        .takes_value(true)
        .multiple(true)
        .help("Environment variables with which the process should be run."),
    )
      .arg(
        Arg::with_name("jdk")
            .long("jdk")
            .takes_value(true)
            .required(false)
            .help("Symlink a JDK from .jdk in the working directory. For local execution, symlinks to the value of this flag. For remote execution, just requests that some JDK is symlinked if this flag has any value. https://github.com/pantsbuild/pants/issues/6416 will make this less weird in the future.")
      )
    .setting(AppSettings::TrailingVarArg)
    .arg(
      Arg::with_name("argv")
        .multiple(true)
        .last(true)
        .required(true),
    )
    .arg(
        Arg::with_name("output-file-path")
            .long("output-file-path")
            .takes_value(true)
            .multiple(true)
            .required(false)
            .help("Path to file that is considered to be output."),
    )
    .arg(
      Arg::with_name("output-directory-path")
          .long("output-directory-path")
          .takes_value(true)
          .multiple(true)
          .required(false)
          .help("Path to directory that is considered to be output."),
    )
    .arg(
      Arg::with_name("materialize-output-to")
          .long("materialize-output-to")
          .takes_value(true)
          .required(false)
          .help("The name of a directory (which may or may not exist), where the output tree will be materialized.")
    )
    .get_matches();

  let argv: Vec<String> = args
    .values_of("argv")
    .unwrap()
    .map(|v| v.to_string())
    .collect();
  let env: BTreeMap<String, String> = match args.values_of("env") {
    Some(values) => values
      .map(|v| {
        let mut parts = v.splitn(2, '=');
        (
          parts.next().unwrap().to_string(),
          parts.next().unwrap_or_default().to_string(),
        )
      })
      .collect(),
    None => BTreeMap::new(),
  };
  let work_dir = args
    .value_of("work-dir")
    .map(PathBuf::from)
    .unwrap_or_else(std::env::temp_dir);
  let local_store_path = args
    .value_of("local-store-path")
    .map(PathBuf::from)
    .unwrap_or_else(fs::Store::default_path);
  let pool = Arc::new(fs::ResettablePool::new("process-executor-".to_owned()));
  let timer_thread = resettable::Resettable::new(|| futures_timer::HelperThread::new().unwrap());
  let server_arg = args.value_of("server");
  let remote_instance_arg = args.value_of("remote-instance-name").map(str::to_owned);
  let output_files = if let Some(values) = args.values_of("output-file-path") {
    values.map(PathBuf::from).collect()
  } else {
    BTreeSet::new()
  };
  let output_directories = if let Some(values) = args.values_of("output-directory-path") {
    values.map(PathBuf::from).collect()
  } else {
    BTreeSet::new()
  };

  let store = match (server_arg, args.value_of("cas-server")) {
    (Some(_server), Some(cas_server)) => {
      let chunk_size =
        value_t!(args.value_of("upload-chunk-bytes"), usize).expect("Bad upload-chunk-bytes flag");

      let root_ca_certs = if let Some(path) = args.value_of("cas-root-ca-cert-file") {
        Some(std::fs::read(path).expect("Error reading root CA certs file"))
      } else {
        None
      };

      let oauth_bearer_token = if let Some(path) = args.value_of("cas-oauth-bearer-token-path") {
        Some(std::fs::read_to_string(path).expect("Error reading oauth bearer token file"))
      } else {
        None
      };

      fs::Store::with_remote(
        local_store_path,
        pool.clone(),
        &[cas_server.to_owned()],
        remote_instance_arg.clone(),
        &root_ca_certs,
        oauth_bearer_token,
        1,
        chunk_size,
        Duration::from_secs(30),
        // TODO: Take a command line arg.
        fs::BackoffConfig::new(Duration::from_secs(1), 1.2, Duration::from_secs(20)).unwrap(),
        3,
        timer_thread.with(|t| t.handle()),
      )
    }
    (None, None) => fs::Store::local_only(local_store_path, pool.clone()),
    _ => panic!("Must specify either both --server and --cas-server or neither."),
  }
  .expect("Error making store");

  let input_files = {
    let fingerprint = Fingerprint::from_hex_string(args.value_of("input-digest").unwrap())
      .expect("Bad input-digest");
    let length = args
      .value_of("input-digest-length")
      .unwrap()
      .parse::<usize>()
      .expect("input-digest-length must be a non-negative number");
    Digest(fingerprint, length)
  };

  let request = process_execution::ExecuteProcessRequest {
    argv,
    env,
    input_files,
    output_files,
    output_directories,
    timeout: Duration::new(15 * 60, 0),
    description: "process_executor".to_string(),
    jdk_home: args.value_of("jdk").map(PathBuf::from),
  };

  let runner: Box<dyn process_execution::CommandRunner> = match server_arg {
    Some(address) => {
      let oauth_bearer_token =
        if let Some(path) = args.value_of("execution-oauth-bearer-token-path") {
          Some(std::fs::read_to_string(path).expect("Error reading oauth bearer token file"))
        } else {
          None
        };

      Box::new(
        process_execution::remote::CommandRunner::new(
          address,
          args.value_of("cache-key-gen-version").map(str::to_owned),
          remote_instance_arg,
          oauth_bearer_token,
          store.clone(),
          timer_thread,
        )
        .expect("Could not initialize remote execution client"),
      ) as Box<dyn process_execution::CommandRunner>
    }
    None => Box::new(process_execution::local::CommandRunner::new(
      store.clone(),
      pool,
      work_dir,
      true,
    )) as Box<dyn process_execution::CommandRunner>,
  };
  let mut rt = tokio::runtime::Runtime::new().unwrap();
  let result = rt.block_on(runner.run(request)).unwrap();

  if let Some(output) = args.value_of("materialize-output-to").map(PathBuf::from) {
    rt.block_on(store.materialize_directory(output, result.output_directory))
      .unwrap();
  };

  print!("{}", String::from_utf8(result.stdout.to_vec()).unwrap());
  eprint!("{}", String::from_utf8(result.stderr.to_vec()).unwrap());

  rt.shutdown_now().wait().unwrap();

  exit(result.exit_code);
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate serde_json;
use serde_json::value::Value;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    ::launch_and_assert(osm2mimir,
                      vec!["--input=./tests/fixtures/three_cities.osm.pbf".into(),
                       "--import-way".into(),
                       "--import-admin".into(),
                       "--level=8".into(),
                       format!("--connection-string={}", es_wrapper.host())],
                       &es_wrapper);

    // Test: Import of Admin
    let city = es_wrapper.search("name:Livry-sur-Seine");
    let nb_hits = city.lookup("hits.total").and_then(|v| v.as_u64()).unwrap_or(0);
    assert_eq!(nb_hits, 1);
    let city_type = city.pointer("/hits/hits/0/_type").and_then(|v| v.as_string()).unwrap_or("");
    assert_eq!(city_type, "admin");

    // Test: search for "Rue des Près"
    let search = es_wrapper.search(r#"name:Rue des Près"#);
    // The first hit should be "Rue des Près"
    let rue_name = search.pointer("/hits/hits/0/_source/name").and_then(|v| v.as_string()).unwrap_or("");
    assert_eq!(rue_name, r#"Rue des Près"#);
    // And there should be only ONE "Rue des Près"
    let street_filter = |street: &Value| {
    	         	let name = street.pointer("/_source/name").and_then(|n| n.as_string()).unwrap_or("");
    	            name == r#"Rue des Près"#
    			};
    let nb = es_wrapper.search_and_filter(r#"name:Rue des Près"#, street_filter).count();
    assert_eq!(nb, 1);

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let street_filter = |street: &Value| {
    	            let name = street.pointer("/_source/name").and_then(|n| n.as_string()).unwrap_or("");
    	            let admin_name = street.pointer("/_source/administrative_regions/0/name").and_then(|n| n.as_string()).unwrap_or("");
    	            name == r#"Rue du Four à Chaux"# && admin_name == r#"Livry-sur-Seine"#
    			};
    let nb = es_wrapper.search_and_filter(r#"name:Rue du Four à Chaux"#, street_filter).count();
    assert_eq!(nb, 6);

    //Test: Streets having the same name in different cities
    let street_filter = |street: &Value| {
                        let name = street.pointer("/_source/name").and_then(|n| n.as_string()).unwrap_or("");
                        let admin_name = street.pointer("/_source/administrative_regions/0/name").and_then(|n| n.as_string()).unwrap_or("");
                        name == r#"Rue du Port"# && admin_name == r#"Melun"#
    			};
    let nb = es_wrapper.search_and_filter(r#"name:Rue du Port"#, street_filter).count();
    assert_eq!(nb, 1);
}
<commit_msg>fix test after rebase<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate serde_json;
use serde_json::value::Value;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    ::launch_and_assert(osm2mimir,
                      vec!["--input=./tests/fixtures/three_cities.osm.pbf".into(),
                       "--import-way".into(),
                       "--import-admin".into(),
                       "--level=8".into(),
                       format!("--connection-string={}", es_wrapper.host())],
                       &es_wrapper);

    // Test: Import of Admin
    let city = es_wrapper.search("label:Livry-sur-Seine");
    let nb_hits = city.pointer("/hits/total").and_then(|v| v.as_u64()).unwrap_or(0);
    assert_eq!(nb_hits, 1);
    let city_type = city.pointer("/hits/hits/0/_type").and_then(|v| v.as_string()).unwrap_or("");
    assert_eq!(city_type, "admin");

    // Test: search for "Rue des Près"
    let search = es_wrapper.search("label:Rue des Près");
    // The first hit should be "Rue des Près"
    let street_label = search.pointer("/hits/hits/0/_source/label").and_then(|v| v.as_string()).unwrap_or("");
    assert_eq!(street_label, "Rue des Près");
    // And there should be only ONE "Rue des Près"
    let street_filter = |street: &Value| {
    	         	let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
    	            label == "Rue des Près"
    			};
    let nb = es_wrapper.search_and_filter(r#"label:Rue des Près"#, street_filter).count();
    assert_eq!(nb, 1);

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let street_filter = |street: &Value| {
    	            let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
    	            let admin_label = street.pointer("/_source/administrative_regions/0/label").and_then(|n| n.as_string()).unwrap_or("");
    	            label == "Rue du Four à Chaux" && admin_label == "Livry-sur-Seine"
    			};
    let nb = es_wrapper.search_and_filter("label:Rue du Four à Chaux", street_filter).count();
    assert_eq!(nb, 6);

    //Test: Streets having the same label in different cities
    let street_filter = |street: &Value| {
                        let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
                        let admin_label = street.pointer("/_source/administrative_regions/0/label").and_then(|n| n.as_string()).unwrap_or("");
                        label == r#"Rue du Port"# && admin_label == r#"Melun"#
    			};
    let nb = es_wrapper.search_and_filter(r#"label:Rue du Port"#, street_filter).count();
    assert_eq!(nb, 1);
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate tuf;

use chrono::prelude::*;
use chrono::offset::Utc;
use std::collections::{HashSet, HashMap};
use tuf::{Tuf, Error};
use tuf::client::{Client, Config};
use tuf::crypto::{PrivateKey, SignatureScheme, KeyId, HashAlgorithm};
use tuf::interchange::{DataInterchange, JsonDataInterchange};
use tuf::metadata::{RoleDefinition, RootMetadata, Role, MetadataVersion, MetadataPath,
                    SignedMetadata, TargetDescription, TargetPath, TargetsMetadata,
                    MetadataDescription, SnapshotMetadata, TimestampMetadata};
use tuf::repository::{EphemeralRepository, Repository};

// Ironically, this is far from simple, but it's as simple as it can be made.

const ED25519_1_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-1.pk8.der");
const ED25519_2_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-2.pk8.der");
const ED25519_3_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-3.pk8.der");
const ED25519_4_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-4.pk8.der");

#[test]
fn main() {
    let mut remote = EphemeralRepository::<JsonDataInterchange>::new();
    let root_key_ids = init_server(&mut remote).unwrap();
    init_client(root_key_ids, remote).unwrap();
}

fn init_client(
    root_key_ids: Vec<KeyId>,
    mut remote: EphemeralRepository<JsonDataInterchange>,
) -> Result<(), Error> {
    let local = EphemeralRepository::<JsonDataInterchange>::new();
    let config = Config::build().finish()?;
    let root = remote.fetch_metadata(
        &Role::Root,
        &MetadataPath::from_role(&Role::Root),
        &MetadataVersion::None,
        config.max_root_size(),
        config.min_bytes_per_second(),
        None,
    )?;

    let tuf = Tuf::<JsonDataInterchange>::from_root_pinned(root, &root_key_ids)?;
    let mut client = Client::new(tuf, config, local, remote)?;
    match client.update_local() {
        Ok(_) => (),
        Err(e) => println!("{:?}", e),
    }
    let _ = client.update_remote()?;
    client.fetch_target(&TargetPath::new("grendel".into())?)
}

fn init_server(remote: &mut EphemeralRepository<JsonDataInterchange>) -> Result<Vec<KeyId>, Error> {
    // in real life, you wouldn't want these keys on the same machine ever
    let root_key = PrivateKey::from_pkcs8(ED25519_1_PK8)?;
    let snapshot_key = PrivateKey::from_pkcs8(ED25519_2_PK8)?;
    let targets_key = PrivateKey::from_pkcs8(ED25519_3_PK8)?;
    let timestamp_key = PrivateKey::from_pkcs8(ED25519_4_PK8)?;

    //// build the root ////

    let keys = vec![
        root_key.public().clone(),
        snapshot_key.public().clone(),
        targets_key.public().clone(),
        timestamp_key.public().clone(),
    ];

    let mut key_ids = HashSet::new();
    key_ids.insert(root_key.key_id().clone());
    let root_def = RoleDefinition::new(1, key_ids)?;

    let mut key_ids = HashSet::new();
    key_ids.insert(snapshot_key.key_id().clone());
    let snapshot_def = RoleDefinition::new(1, key_ids)?;

    let mut key_ids = HashSet::new();
    key_ids.insert(targets_key.key_id().clone());
    let targets_def = RoleDefinition::new(1, key_ids)?;

    let mut key_ids = HashSet::new();
    key_ids.insert(timestamp_key.key_id().clone());
    let timestamp_def = RoleDefinition::new(1, key_ids)?;

    let root = RootMetadata::new(
        1,
        Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
        false,
        keys,
        root_def,
        snapshot_def,
        targets_def,
        timestamp_def,
    )?;

    let signed = SignedMetadata::<JsonDataInterchange, RootMetadata>::new(
        &root,
        &root_key,
        SignatureScheme::Ed25519,
    )?;

    remote.store_metadata(
        &Role::Root,
        &MetadataPath::new("root".into())?,
        &MetadataVersion::Number(1),
        &signed,
    )?;
    remote.store_metadata(
        &Role::Root,
        &MetadataPath::new("root".into())?,
        &MetadataVersion::None,
        &signed,
    )?;

    //// build the targets ////

    let target_file: &[u8] = b"things fade, alternatives exclude";
    let target_path = TargetPath::new("grendel".into())?;
    let target_description = TargetDescription::from_reader(target_file, &[HashAlgorithm::Sha256])?;
    let _ = remote.store_target(target_file, &target_path);

    let mut target_map = HashMap::new();
    let _ = target_map.insert(target_path, target_description);
    let targets = TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), target_map, None)?;

    let signed = SignedMetadata::<JsonDataInterchange, TargetsMetadata>::new(
        &targets,
        &targets_key,
        SignatureScheme::Ed25519,
    )?;

    remote.store_metadata(
        &Role::Targets,
        &MetadataPath::new("targets".into())?,
        &MetadataVersion::Number(1),
        &signed,
    )?;
    remote.store_metadata(
        &Role::Targets,
        &MetadataPath::new("targets".into())?,
        &MetadataVersion::None,
        &signed,
    )?;

    let targets_bytes =
        JsonDataInterchange::canonicalize(&JsonDataInterchange::serialize(&signed)?)?;

    //// build the snapshot ////
    let mut meta_map = HashMap::new();
    let path = MetadataPath::new("targets".into())?;
    let desc = MetadataDescription::from_reader(&*targets_bytes, 1, &[HashAlgorithm::Sha256])?;
    let _ = meta_map.insert(path, desc);
    let snapshot = SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map)?;

    let signed = SignedMetadata::<JsonDataInterchange, SnapshotMetadata>::new(
        &snapshot,
        &snapshot_key,
        SignatureScheme::Ed25519,
    )?;

    remote.store_metadata(
        &Role::Snapshot,
        &MetadataPath::new("snapshot".into())?,
        &MetadataVersion::Number(1),
        &signed,
    )?;
    remote.store_metadata(
        &Role::Snapshot,
        &MetadataPath::new("snapshot".into())?,
        &MetadataVersion::None,
        &signed,
    )?;

    let snapshot_bytes =
        JsonDataInterchange::canonicalize(&JsonDataInterchange::serialize(&signed)?)?;

    //// build the timestamp ////
    let mut meta_map = HashMap::new();
    let path = MetadataPath::new("snapshot".into())?;
    let desc = MetadataDescription::from_reader(&*snapshot_bytes, 1, &[HashAlgorithm::Sha256])?;
    let _ = meta_map.insert(path, desc);
    let timestamp = TimestampMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map)?;

    let signed = SignedMetadata::<JsonDataInterchange, TimestampMetadata>::new(
        &timestamp,
        &timestamp_key,
        SignatureScheme::Ed25519,
    )?;

    remote.store_metadata(
        &Role::Timestamp,
        &MetadataPath::new("timestamp".into())?,
        &MetadataVersion::Number(1),
        &signed,
    )?;
    remote.store_metadata(
        &Role::Timestamp,
        &MetadataPath::new("timestamp".into())?,
        &MetadataVersion::None,
        &signed,
    )?;

    Ok(vec![root_key.key_id().clone()])
}
<commit_msg>slightly better tests<commit_after>extern crate chrono;
#[macro_use]
extern crate maplit;
extern crate tuf;

use chrono::prelude::*;
use chrono::offset::Utc;
use tuf::{Tuf, Error};
use tuf::client::{Client, Config};
use tuf::crypto::{PrivateKey, SignatureScheme, KeyId, HashAlgorithm};
use tuf::interchange::{DataInterchange, JsonDataInterchange};
use tuf::metadata::{RoleDefinition, RootMetadata, Role, MetadataVersion, MetadataPath,
                    SignedMetadata, TargetDescription, TargetPath, TargetsMetadata,
                    MetadataDescription, SnapshotMetadata, TimestampMetadata};
use tuf::repository::{EphemeralRepository, Repository};

// Ironically, this is far from simple, but it's as simple as it can be made.

const ED25519_1_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-1.pk8.der");
const ED25519_2_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-2.pk8.der");
const ED25519_3_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-3.pk8.der");
const ED25519_4_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-4.pk8.der");

#[test]
fn main() {
    let mut remote = EphemeralRepository::<JsonDataInterchange>::new();
    let root_key_ids = init_server(&mut remote).unwrap();
    init_client(root_key_ids, remote).unwrap();
}

fn init_client(
    root_key_ids: Vec<KeyId>,
    mut remote: EphemeralRepository<JsonDataInterchange>,
) -> Result<(), Error> {
    let local = EphemeralRepository::<JsonDataInterchange>::new();
    let config = Config::build().finish()?;
    let root = remote.fetch_metadata(
        &Role::Root,
        &MetadataPath::from_role(&Role::Root),
        &MetadataVersion::None,
        config.max_root_size(),
        config.min_bytes_per_second(),
        None,
    )?;

    let tuf = Tuf::<JsonDataInterchange>::from_root_pinned(root, &root_key_ids)?;
    let mut client = Client::new(tuf, config, local, remote)?;
    match client.update_local() {
        Ok(_) => (),
        Err(e) => println!("{:?}", e),
    }
    let _ = client.update_remote()?;
    client.fetch_target(&TargetPath::new("grendel".into())?)
}

fn init_server(remote: &mut EphemeralRepository<JsonDataInterchange>) -> Result<Vec<KeyId>, Error> {
    // in real life, you wouldn't want these keys on the same machine ever
    let root_key = PrivateKey::from_pkcs8(ED25519_1_PK8)?;
    let snapshot_key = PrivateKey::from_pkcs8(ED25519_2_PK8)?;
    let targets_key = PrivateKey::from_pkcs8(ED25519_3_PK8)?;
    let timestamp_key = PrivateKey::from_pkcs8(ED25519_4_PK8)?;

    //// build the root ////

    let keys = vec![
        root_key.public().clone(),
        snapshot_key.public().clone(),
        targets_key.public().clone(),
        timestamp_key.public().clone(),
    ];

    let root_def = RoleDefinition::new(1, hashset!(root_key.key_id().clone()))?;
    let snapshot_def = RoleDefinition::new(1, hashset!(snapshot_key.key_id().clone()))?;
    let targets_def = RoleDefinition::new(1, hashset!(targets_key.key_id().clone()))?;
    let timestamp_def = RoleDefinition::new(1, hashset!(timestamp_key.key_id().clone()))?;

    let root = RootMetadata::new(
        1,
        Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
        false,
        keys,
        root_def,
        snapshot_def,
        targets_def,
        timestamp_def,
    )?;

    let signed = SignedMetadata::<JsonDataInterchange, RootMetadata>::new(
        &root,
        &root_key,
        SignatureScheme::Ed25519,
    )?;

    remote.store_metadata(
        &Role::Root,
        &MetadataPath::new("root".into())?,
        &MetadataVersion::Number(1),
        &signed,
    )?;
    remote.store_metadata(
        &Role::Root,
        &MetadataPath::new("root".into())?,
        &MetadataVersion::None,
        &signed,
    )?;

    //// build the targets ////

    let target_file: &[u8] = b"things fade, alternatives exclude";
    let target_path = TargetPath::new("grendel".into())?;
    let target_description = TargetDescription::from_reader(target_file, &[HashAlgorithm::Sha256])?;
    let _ = remote.store_target(target_file, &target_path);

    let target_map = hashmap!(target_path => target_description);
    let targets = TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), target_map, None)?;

    let signed = SignedMetadata::<JsonDataInterchange, TargetsMetadata>::new(
        &targets,
        &targets_key,
        SignatureScheme::Ed25519,
    )?;

    remote.store_metadata(
        &Role::Targets,
        &MetadataPath::new("targets".into())?,
        &MetadataVersion::Number(1),
        &signed,
    )?;
    remote.store_metadata(
        &Role::Targets,
        &MetadataPath::new("targets".into())?,
        &MetadataVersion::None,
        &signed,
    )?;

    let targets_bytes =
        JsonDataInterchange::canonicalize(&JsonDataInterchange::serialize(&signed)?)?;

    //// build the snapshot ////
    let meta_map = hashmap! {
        MetadataPath::new("targets".into())? =>
            MetadataDescription::from_reader(&*targets_bytes, 1, &[HashAlgorithm::Sha256])?,
    };
    let snapshot = SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map)?;

    let signed = SignedMetadata::<JsonDataInterchange, SnapshotMetadata>::new(
        &snapshot,
        &snapshot_key,
        SignatureScheme::Ed25519,
    )?;

    remote.store_metadata(
        &Role::Snapshot,
        &MetadataPath::new("snapshot".into())?,
        &MetadataVersion::Number(1),
        &signed,
    )?;
    remote.store_metadata(
        &Role::Snapshot,
        &MetadataPath::new("snapshot".into())?,
        &MetadataVersion::None,
        &signed,
    )?;

    let snapshot_bytes =
        JsonDataInterchange::canonicalize(&JsonDataInterchange::serialize(&signed)?)?;

    //// build the timestamp ////
    let meta_map = hashmap! {
        MetadataPath::new("snapshot".into())? =>
            MetadataDescription::from_reader(&*snapshot_bytes, 1, &[HashAlgorithm::Sha256])?,
    };
    let timestamp = TimestampMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map)?;

    let signed = SignedMetadata::<JsonDataInterchange, TimestampMetadata>::new(
        &timestamp,
        &timestamp_key,
        SignatureScheme::Ed25519,
    )?;

    remote.store_metadata(
        &Role::Timestamp,
        &MetadataPath::new("timestamp".into())?,
        &MetadataVersion::Number(1),
        &signed,
    )?;
    remote.store_metadata(
        &Role::Timestamp,
        &MetadataPath::new("timestamp".into())?,
        &MetadataVersion::None,
        &signed,
    )?;

    Ok(vec![root_key.key_id().clone()])
}
<|endoftext|>


<commit_before>extern crate kaiseki;

use kaiseki::input;

#[test]
fn test_test1() {
  static OUTPUT: &'static str = include_str!("tangling/test1/output");

  let files = ["tests/tangling/test1/000-file1", "tests/tangling/test1/001-file2"];
  let files: Vec<String> = files.iter().map(|str| str.to_string()).collect();
  let files = input::open_files(files).unwrap();

  let output_options = kaiseki::OutputOptions {
    comment: None
  };

  let (output, errors) = kaiseki::tangle_output(files, output_options);

  assert_eq!(errors.len(), 0);
  for (line1, line2) in OUTPUT.lines().zip(output) {
    assert_eq!(line1, &line2 as &str);
  }
}

#[test]
fn test_test2() {
  static OUTPUT: &'static str = include_str!("tangling/test2/output");

  let files = [ "tests/tangling/test2/000-file1"
              , "tests/tangling/test2/001-file2"
              , "tests/tangling/test2/002-file3"
              ];
  let files: Vec<String> = files.iter().map(|str| str.to_string()).collect();
  let files = input::open_files(files).unwrap();

  let output_options = kaiseki::OutputOptions {
    comment: None
  };

  let (output, errors) = kaiseki::tangle_output(files, output_options);

  assert_eq!(errors.len(), 0);
  for (line1, line2) in OUTPUT.lines().zip(output) {
    assert_eq!(line1, &line2 as &str);
  }
}
<commit_msg>add test2<commit_after>extern crate kaiseki;

use kaiseki::input;

#[test]
fn test_test1() {
  static OUTPUT: &'static str = include_str!("tangling/test1/output");

  let files = ["tests/tangling/test1/000-file1", "tests/tangling/test1/001-file2"];
  let files: Vec<String> = files.iter().map(|str| str.to_string()).collect();
  let files = input::open_files(files).unwrap();

  let output_options = kaiseki::OutputOptions {
    comment: None
  };

  let (output, errors) = kaiseki::tangle_output(files, output_options);

  assert_eq!(errors.len(), 0);
  for (line1, line2) in OUTPUT.lines().zip(output) {
    assert_eq!(line1, &line2 as &str);
  }
}

#[test]
fn test_test2() {
  static OUTPUT: &'static str = include_str!("tangling/test2/output");

  let files = [
    "000-file1",
    "001-file2",
    "002-file3"
  ];

  let files: Vec<String> = files.iter().map(|str| {
    let mut filepath = String::new();
    filepath.push_str("tests/tangling/test2/");
    filepath.push_str(str);
    filepath
  })
  .collect();

  let files = input::open_files(files).unwrap();

  let output_options = kaiseki::OutputOptions {
    comment: None
  };

  let (output, errors) = kaiseki::tangle_output(files, output_options);

  assert_eq!(errors.len(), 0);
  for (line1, line2) in OUTPUT.lines().zip(output) {
    assert_eq!(line1, &line2 as &str);
  }
}
<|endoftext|>


<commit_before>// run-pass

#![allow(warnings)]

use std::iter::Zip;

fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter }

fn main() { }
<commit_msg>Add a test to ensure Fuse stays covariant<commit_after>// run-pass

#![allow(dead_code)]

use std::iter::{Fuse, Zip};

fn fuse_covariant<'a, I>(iter: Fuse<&'static I>) -> Fuse<&'a I> { iter }
fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter }

fn main() { }
<|endoftext|>


<commit_before>//! # Functions and types used by generated protobuf code
//!
//! These are not considered to be public API of rust-protobuf,
//! so they can be changed any time (provided compatibility with
//! previously generated code is preserved).

pub use crate::cached_size::CachedSize;
use crate::coded_input_stream::CodedInputStream;
use crate::coded_output_stream::CodedOutputStream;
use crate::enums::Enum;
use crate::error::Result;
pub use crate::lazy::Lazy;
pub use crate::wire_format::WireType;
use crate::zigzag::*;
use crate::EnumOrUnknown;
use crate::Message;
use crate::MessageField;

pub(crate) mod map;
pub(crate) mod repeated;
pub(crate) mod unsorted;
pub use map::compute_map_size;
pub use map::read_map_into;
pub use map::write_map_with_cached_sizes;
pub use repeated::read_repeated_packed_enum_or_unknown_into;
pub use unsorted::read_unknown_or_skip_group;
pub use unsorted::unknown_fields_size;

use crate::varint::encode::encoded_varint64_len;

/// Given `u64` value compute varint encoded length.
pub fn compute_raw_varint64_size(value: u64) -> u64 {
    encoded_varint64_len(value) as u64
}

/// Given `u32` value compute varint encoded length.
pub(crate) fn compute_raw_varint32_size(value: u32) -> u64 {
    compute_raw_varint64_size(value as u64)
}

/// Fixed size integers.
pub trait ProtobufFixed {
    /// Size of this fixed type in bytes.
    const LEN: u32;
}

/// Helper trait implemented by integer types which could be encoded as varint.
pub trait ProtobufVarint {
    /// Size of self when encoded as varint.
    fn len_varint(&self) -> u64;
}

/// Helper trait implemented by integer types which could be encoded as zigzag varint.
pub trait ProtobufVarintZigzag {
    /// Size of self when encoded as zigzag varint.
    fn len_varint_zigzag(&self) -> u64;
}

impl ProtobufVarint for u64 {
    fn len_varint(&self) -> u64 {
        compute_raw_varint64_size(*self)
    }
}

impl ProtobufVarint for u32 {
    fn len_varint(&self) -> u64 {
        (*self as u64).len_varint()
    }
}

impl ProtobufVarint for i64 {
    fn len_varint(&self) -> u64 {
        // same as length of u64
        (*self as u64).len_varint()
    }
}

impl ProtobufVarintZigzag for i64 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint64_size(encode_zig_zag_64(*self))
    }
}

impl ProtobufVarint for i32 {
    fn len_varint(&self) -> u64 {
        // sign-extend and then compute
        (*self as i64).len_varint()
    }
}

impl ProtobufVarintZigzag for i32 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint32_size(encode_zig_zag_32(*self))
    }
}

impl ProtobufVarint for bool {
    fn len_varint(&self) -> u64 {
        1
    }
}

impl ProtobufFixed for u32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for i32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for u64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for i64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for f32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for f64 {
    const LEN: u32 = 8;
}

/// Technically `bool` is not fixed, but it can be considered as fixed
/// for the purpose of encoding.
impl ProtobufFixed for bool {
    const LEN: u32 = 1;
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_data_size<T: ProtobufVarint>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint() as u64)
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_zigzag_data_size<T: ProtobufVarintZigzag>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint_zigzag())
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed enum field, excluding length and tag.
pub fn vec_packed_enum_or_unknown_data_size<E: Enum>(vec: &[EnumOrUnknown<E>]) -> u64 {
    vec.iter()
        .map(|e| compute_raw_varint32_size(e.value() as u32))
        .fold(0, |a, i| a + i)
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_size<T: ProtobufVarint>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_zigzag_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_enum_or_unknown_size<E: Enum>(
    field_number: u32,
    vec: &[EnumOrUnknown<E>],
) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_enum_or_unknown_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute data size of fixed encoding of repeated field data.
pub(crate) fn vec_packed_fixed_data_size<V: ProtobufFixed>(vec: &[V]) -> u64 {
    (vec.len() as u64) * (V::LEN as u64)
}

/// Compute field size (data plus header) of fixed encoding of repeated field.
pub fn vec_packed_fixed_size<V: ProtobufFixed>(field_number: u32, vec: &[V]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_fixed_data_size::<V>(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute tag size. Size of tag does not depend on wire type.
pub fn tag_size(field_number: u32) -> u64 {
    encoded_varint64_len((field_number as u64) << 3) as u64
}

/// Size of encoded `sint32` value.
pub fn sint32_size_no_tag(value: i32) -> u64 {
    compute_raw_varint32_size(encode_zig_zag_32(value))
}

/// Size of encoded `sint64` value.
pub fn sint64_size_no_tag(value: i64) -> u64 {
    compute_raw_varint64_size(encode_zig_zag_64(value))
}

/// Size of encoded `int32` value.
pub fn int32_size_no_tag(value: i32) -> u64 {
    value.len_varint()
}

/// Size of encoded `int64` value.
pub fn int64_size_no_tag(value: i64) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint32` value.
pub fn uint32_size_no_tag(value: u32) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint64` value.
pub fn uint64_size_no_tag(value: u64) -> u64 {
    value.len_varint()
}

/// Size of encoded enum field value.
pub fn enum_or_unknown_size_no_tag<E: Enum>(value: EnumOrUnknown<E>) -> u64 {
    value.value().len_varint() as u64
}

/// Size of encoded bytes field.
pub fn bytes_size_no_tag(bytes: &[u8]) -> u64 {
    compute_raw_varint64_size(bytes.len() as u64) + bytes.len() as u64
}

/// Size of encoded string field.
pub fn string_size_no_tag(s: &str) -> u64 {
    bytes_size_no_tag(s.as_bytes())
}

/// Read singular `message` field.
pub fn read_singular_message_into_field<M>(
    is: &mut CodedInputStream,
    target: &mut MessageField<M>,
) -> Result<()>
where
    M: Message,
{
    let mut m = M::new();
    is.merge_message(&mut m)?;
    *target = MessageField::some(m);
    Ok(())
}

/// Write message with field number and length to the stream.
pub fn write_message_field_with_cached_size<M>(
    field_number: u32,
    message: &M,
    os: &mut CodedOutputStream,
) -> Result<()>
where
    M: Message,
{
    os.write_tag(field_number, WireType::LengthDelimited)?;
    os.write_raw_varint32(message.cached_size())?;
    message.write_to_with_cached_sizes(os)
}
<commit_msg>Dead code<commit_after>//! # Functions and types used by generated protobuf code
//!
//! These are not considered to be public API of rust-protobuf,
//! so they can be changed any time (provided compatibility with
//! previously generated code is preserved).

pub use crate::cached_size::CachedSize;
use crate::coded_input_stream::CodedInputStream;
use crate::coded_output_stream::CodedOutputStream;
use crate::enums::Enum;
use crate::error::Result;
pub use crate::lazy::Lazy;
pub use crate::wire_format::WireType;
use crate::zigzag::*;
use crate::EnumOrUnknown;
use crate::Message;
use crate::MessageField;

pub(crate) mod map;
pub(crate) mod repeated;
pub(crate) mod unsorted;
pub use map::compute_map_size;
pub use map::read_map_into;
pub use map::write_map_with_cached_sizes;
pub use repeated::read_repeated_packed_enum_or_unknown_into;
pub use unsorted::read_unknown_or_skip_group;
pub use unsorted::unknown_fields_size;

use crate::varint::encode::encoded_varint64_len;

/// Given `u64` value compute varint encoded length.
pub fn compute_raw_varint64_size(value: u64) -> u64 {
    encoded_varint64_len(value) as u64
}

/// Given `u32` value compute varint encoded length.
pub(crate) fn compute_raw_varint32_size(value: u32) -> u64 {
    compute_raw_varint64_size(value as u64)
}

/// Fixed size integers.
pub trait ProtobufFixed {
    /// Size of this fixed type in bytes.
    const LEN: u32;
}

/// Helper trait implemented by integer types which could be encoded as varint.
pub trait ProtobufVarint {
    /// Size of self when encoded as varint.
    fn len_varint(&self) -> u64;
}

/// Helper trait implemented by integer types which could be encoded as zigzag varint.
pub trait ProtobufVarintZigzag {
    /// Size of self when encoded as zigzag varint.
    fn len_varint_zigzag(&self) -> u64;
}

impl ProtobufVarint for u64 {
    fn len_varint(&self) -> u64 {
        compute_raw_varint64_size(*self)
    }
}

impl ProtobufVarint for u32 {
    fn len_varint(&self) -> u64 {
        (*self as u64).len_varint()
    }
}

impl ProtobufVarint for i64 {
    fn len_varint(&self) -> u64 {
        // same as length of u64
        (*self as u64).len_varint()
    }
}

impl ProtobufVarintZigzag for i64 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint64_size(encode_zig_zag_64(*self))
    }
}

impl ProtobufVarint for i32 {
    fn len_varint(&self) -> u64 {
        // sign-extend and then compute
        (*self as i64).len_varint()
    }
}

impl ProtobufVarintZigzag for i32 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint32_size(encode_zig_zag_32(*self))
    }
}

impl ProtobufVarint for bool {
    fn len_varint(&self) -> u64 {
        1
    }
}

impl ProtobufFixed for u32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for i32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for u64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for i64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for f32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for f64 {
    const LEN: u32 = 8;
}

/// Technically `bool` is not fixed, but it can be considered as fixed
/// for the purpose of encoding.
impl ProtobufFixed for bool {
    const LEN: u32 = 1;
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_data_size<T: ProtobufVarint>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint() as u64)
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_zigzag_data_size<T: ProtobufVarintZigzag>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint_zigzag())
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed enum field, excluding length and tag.
pub fn vec_packed_enum_or_unknown_data_size<E: Enum>(vec: &[EnumOrUnknown<E>]) -> u64 {
    vec.iter()
        .map(|e| compute_raw_varint32_size(e.value() as u32))
        .fold(0, |a, i| a + i)
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_size<T: ProtobufVarint>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_zigzag_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_enum_or_unknown_size<E: Enum>(
    field_number: u32,
    vec: &[EnumOrUnknown<E>],
) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_enum_or_unknown_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute data size of fixed encoding of repeated field data.
pub(crate) fn vec_packed_fixed_data_size<V: ProtobufFixed>(vec: &[V]) -> u64 {
    (vec.len() as u64) * (V::LEN as u64)
}

/// Compute field size (data plus header) of fixed encoding of repeated field.
pub fn vec_packed_fixed_size<V: ProtobufFixed>(field_number: u32, vec: &[V]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_fixed_data_size::<V>(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute tag size. Size of tag does not depend on wire type.
pub fn tag_size(field_number: u32) -> u64 {
    encoded_varint64_len((field_number as u64) << 3) as u64
}

/// Size of encoded `sint32` value.
pub fn sint32_size_no_tag(value: i32) -> u64 {
    compute_raw_varint32_size(encode_zig_zag_32(value))
}

/// Size of encoded `sint64` value.
pub fn sint64_size_no_tag(value: i64) -> u64 {
    compute_raw_varint64_size(encode_zig_zag_64(value))
}

/// Size of encoded `int32` value.
pub fn int32_size_no_tag(value: i32) -> u64 {
    value.len_varint()
}

/// Size of encoded `int64` value.
pub fn int64_size_no_tag(value: i64) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint32` value.
pub fn uint32_size_no_tag(value: u32) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint64` value.
pub fn uint64_size_no_tag(value: u64) -> u64 {
    value.len_varint()
}

/// Size of encoded bytes field.
pub fn bytes_size_no_tag(bytes: &[u8]) -> u64 {
    compute_raw_varint64_size(bytes.len() as u64) + bytes.len() as u64
}

/// Size of encoded string field.
pub fn string_size_no_tag(s: &str) -> u64 {
    bytes_size_no_tag(s.as_bytes())
}

/// Read singular `message` field.
pub fn read_singular_message_into_field<M>(
    is: &mut CodedInputStream,
    target: &mut MessageField<M>,
) -> Result<()>
where
    M: Message,
{
    let mut m = M::new();
    is.merge_message(&mut m)?;
    *target = MessageField::some(m);
    Ok(())
}

/// Write message with field number and length to the stream.
pub fn write_message_field_with_cached_size<M>(
    field_number: u32,
    message: &M,
    os: &mut CodedOutputStream,
) -> Result<()>
where
    M: Message,
{
    os.write_tag(field_number, WireType::LengthDelimited)?;
    os.write_raw_varint32(message.cached_size())?;
    message.write_to_with_cached_sizes(os)
}
<|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/. */

//! CSS handling for the specified value of
//! [`image`][image]s
//!
//! [image]: https://drafts.csswg.org/css-images/#image-values

use Atom;
use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
#[cfg(feature = "servo")]
use servo_url::ServoUrl;
use std::f32::consts::PI;
use std::fmt;
use style_traits::ToCss;
use values::{Either, None_};
use values::generics::image::{Circle, CompatMode, Ellipse, ColorStop as GenericColorStop};
use values::generics::image::{EndingShape as GenericEndingShape, Gradient as GenericGradient};
use values::generics::image::{GradientItem as GenericGradientItem, GradientKind as GenericGradientKind};
use values::generics::image::{Image as GenericImage, ImageRect as GenericImageRect};
use values::generics::image::{LineDirection as GenericsLineDirection, ShapeExtent};
use values::specified::{Angle, CSSColor, Length, LengthOrPercentage, NumberOrPercentage, Percentage};
use values::specified::position::{Position, X, Y};
use values::specified::url::SpecifiedUrl;

/// A specified image layer.
pub type ImageLayer = Either<None_, Image>;

/// Specified values for an image according to CSS-IMAGES.
/// https://drafts.csswg.org/css-images/#image-values
pub type Image = GenericImage<Gradient, ImageRect>;

/// Specified values for a CSS gradient.
/// https://drafts.csswg.org/css-images/#gradients
pub type Gradient = GenericGradient<
    LineDirection,
    Length,
    LengthOrPercentage,
    Position,
    CSSColor,
>;

/// A specified gradient kind.
pub type GradientKind = GenericGradientKind<
    LineDirection,
    Length,
    LengthOrPercentage,
    Position,
>;

/// A specified gradient line direction.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum LineDirection {
    /// An angular direction.
    Angle(Angle),
    /// A horizontal direction.
    Horizontal(X),
    /// A vertical direction.
    Vertical(Y),
    /// A direction towards a corner of a box.
    Corner(X, Y),
}

/// A specified ending shape.
pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;

/// A specified gradient item.
pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>;

/// A computed color stop.
pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>;

/// Specified values for `moz-image-rect`
/// -moz-image-rect(<uri>, top, right, bottom, left);
pub type ImageRect = GenericImageRect<NumberOrPercentage>;

impl Parse for Image {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> {
        if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
            return Ok(GenericImage::Url(url));
        }
        if let Ok(gradient) = input.try(|input| Gradient::parse_function(context, input)) {
            return Ok(GenericImage::Gradient(gradient));
        }
        if let Ok(image_rect) = input.try(|input| ImageRect::parse(context, input)) {
            return Ok(GenericImage::Rect(image_rect));
        }

        Ok(GenericImage::Element(Image::parse_element(input)?))
    }
}

impl Image {
    /// Creates an already specified image value from an already resolved URL
    /// for insertion in the cascade.
    #[cfg(feature = "servo")]
    pub fn for_cascade(url: ServoUrl) -> Self {
        GenericImage::Url(SpecifiedUrl::for_cascade(url))
    }

    /// Parses a `-moz-element(# <element-id>)`.
    fn parse_element(input: &mut Parser) -> Result<Atom, ()> {
        input.try(|i| i.expect_function_matching("-moz-element"))?;
        input.parse_nested_block(|i| {
            match i.next()? {
                Token::IDHash(id) => Ok(Atom::from(id)),
                _ => Err(()),
            }
        })
    }
}

impl Gradient {
    /// Parses a gradient from the given arguments.
    pub fn parse_function(context: &ParserContext, input: &mut Parser) -> Result<Gradient, ()> {
        enum Shape {
            Linear,
            Radial,
        }

        let (shape, repeating, compat_mode) = match_ignore_ascii_case! { &try!(input.expect_function()),
            "linear-gradient" => {
                (Shape::Linear, false, CompatMode::Modern)
            },
            "-webkit-linear-gradient" => {
                (Shape::Linear, false, CompatMode::WebKit)
            },
            "repeating-linear-gradient" => {
                (Shape::Linear, true, CompatMode::Modern)
            },
            "-webkit-repeating-linear-gradient" => {
                (Shape::Linear, true, CompatMode::WebKit)
            },
            "radial-gradient" => {
                (Shape::Radial, false, CompatMode::Modern)
            },
            "-webkit-radial-gradient" => {
                (Shape::Radial, false, CompatMode::WebKit)
            },
            "repeating-radial-gradient" => {
                (Shape::Radial, true, CompatMode::Modern)
            },
            "-webkit-repeating-radial-gradient" => {
                (Shape::Radial, true, CompatMode::WebKit)
            },
            _ => { return Err(()); }
        };

        let (kind, items) = input.parse_nested_block(|i| {
            let shape = match shape {
                Shape::Linear => GradientKind::parse_linear(context, i, compat_mode)?,
                Shape::Radial => GradientKind::parse_radial(context, i, compat_mode)?,
            };
            let items = Gradient::parse_items(context, i)?;
            Ok((shape, items))
        })?;

        if items.len() < 2 {
            return Err(());
        }

        Ok(Gradient {
            items: items,
            repeating: repeating,
            kind: kind,
            compat_mode: compat_mode,
        })
    }

    fn parse_items(context: &ParserContext, input: &mut Parser) -> Result<Vec<GradientItem>, ()> {
        let mut seen_stop = false;
        let items = try!(input.parse_comma_separated(|input| {
            if seen_stop {
                if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) {
                    seen_stop = false;
                    return Ok(GenericGradientItem::InterpolationHint(hint));
                }
            }
            seen_stop = true;
            ColorStop::parse(context, input).map(GenericGradientItem::ColorStop)
        }));
        if !seen_stop || items.len() < 2 {
            return Err(());
        }
        Ok(items)
    }
}

impl GradientKind {
    fn parse_linear(context: &ParserContext,
                    input: &mut Parser,
                    compat_mode: CompatMode)
                    -> Result<Self, ()> {
        let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode)) {
            input.expect_comma()?;
            d
        } else {
            LineDirection::Vertical(Y::Bottom)
        };
        Ok(GenericGradientKind::Linear(direction))
    }

    fn parse_radial(context: &ParserContext,
                    input: &mut Parser,
                    compat_mode: CompatMode)
                    -> Result<Self, ()> {
        let (shape, position) = if compat_mode == CompatMode::Modern {
            let shape = input.try(|i| EndingShape::parse(context, i, compat_mode));
            let position = input.try(|i| {
                i.expect_ident_matching("at")?;
                Position::parse(context, i)
            });
            (shape, position)
        } else {
            let position = input.try(|i| Position::parse(context, i));
            let shape = input.try(|i| {
                if position.is_ok() {
                    i.expect_comma()?;
                }
                EndingShape::parse(context, i, compat_mode)
            });
            (shape, position)
        };

        if shape.is_ok() || position.is_ok() {
            input.expect_comma()?;
        }

        let shape = shape.unwrap_or({
            GenericEndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner))
        });
        let position = position.unwrap_or(Position::center());
        Ok(GenericGradientKind::Radial(shape, position))
    }
}

impl GenericsLineDirection for LineDirection {
    fn points_downwards(&self) -> bool {
        match *self {
            LineDirection::Angle(ref angle) => angle.radians() == PI,
            LineDirection::Vertical(Y::Bottom) => true,
            _ => false,
        }
    }

    fn to_css<W>(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result
        where W: fmt::Write
    {
        match *self {
            LineDirection::Angle(angle) => {
                angle.to_css(dest)
            },
            LineDirection::Horizontal(x) => {
                if compat_mode == CompatMode::Modern {
                    dest.write_str("to ")?;
                }
                x.to_css(dest)
            },
            LineDirection::Vertical(y) => {
                if compat_mode == CompatMode::Modern {
                    dest.write_str("to ")?;
                }
                y.to_css(dest)
            },
            LineDirection::Corner(x, y) => {
                if compat_mode == CompatMode::Modern {
                    dest.write_str("to ")?;
                }
                x.to_css(dest)?;
                dest.write_str(" ")?;
                y.to_css(dest)
            }
        }
    }
}

impl LineDirection {
    fn parse(context: &ParserContext,
             input: &mut Parser,
             compat_mode: CompatMode)
             -> Result<Self, ()> {
        if let Ok(angle) = input.try(|i| Angle::parse_with_unitless(context, i)) {
            return Ok(LineDirection::Angle(angle));
        }
        input.try(|i| {
            if compat_mode == CompatMode::Modern {
                i.expect_ident_matching("to")?;
            }
            if let Ok(x) = i.try(X::parse) {
                if let Ok(y) = i.try(Y::parse) {
                    return Ok(LineDirection::Corner(x, y));
                }
                return Ok(LineDirection::Horizontal(x));
            }
            let y = Y::parse(i)?;
            if let Ok(x) = i.try(X::parse) {
                return Ok(LineDirection::Corner(x, y));
            }
            Ok(LineDirection::Vertical(y))
        })
    }
}

impl EndingShape {
    fn parse(context: &ParserContext,
             input: &mut Parser,
             compat_mode: CompatMode)
             -> Result<Self, ()> {
        if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
            if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
                return Ok(GenericEndingShape::Circle(Circle::Extent(extent)));
            }
            let _ = input.try(|i| i.expect_ident_matching("ellipse"));
            return Ok(GenericEndingShape::Ellipse(Ellipse::Extent(extent)));
        }
        if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
            if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
                return Ok(GenericEndingShape::Circle(Circle::Extent(extent)));
            }
            if compat_mode == CompatMode::Modern {
                if let Ok(length) = input.try(|i| Length::parse(context, i)) {
                    return Ok(GenericEndingShape::Circle(Circle::Radius(length)));
                }
            }
            return Ok(GenericEndingShape::Circle(Circle::Extent(ShapeExtent::FarthestCorner)));
        }
        if input.try(|i| i.expect_ident_matching("ellipse")).is_ok() {
            if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
                return Ok(GenericEndingShape::Ellipse(Ellipse::Extent(extent)));
            }
            if compat_mode == CompatMode::Modern {
                let pair: Result<_, ()> = input.try(|i| {
                    let x = LengthOrPercentage::parse(context, i)?;
                    let y = LengthOrPercentage::parse(context, i)?;
                    Ok((x, y))
                });
                if let Ok((x, y)) = pair {
                    return Ok(GenericEndingShape::Ellipse(Ellipse::Radii(x, y)));
                }
            }
            return Ok(GenericEndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)));
        }
        if let Ok(length) = input.try(|i| Length::parse(context, i)) {
            if let Ok(y) = input.try(|i| LengthOrPercentage::parse(context, i)) {
                if compat_mode == CompatMode::Modern {
                    let _ = input.try(|i| i.expect_ident_matching("ellipse"));
                }
                return Ok(GenericEndingShape::Ellipse(Ellipse::Radii(length.into(), y)));
            }
            if compat_mode == CompatMode::Modern {
                let y = input.try(|i| {
                    i.expect_ident_matching("ellipse")?;
                    LengthOrPercentage::parse(context, i)
                });
                if let Ok(y) = y {
                    return Ok(GenericEndingShape::Ellipse(Ellipse::Radii(length.into(), y)));
                }
                let _ = input.try(|i| i.expect_ident_matching("circle"));
            }
            return Ok(GenericEndingShape::Circle(Circle::Radius(length)));
        }
        input.try(|i| {
            let x = Percentage::parse(context, i)?;
            let y = if let Ok(y) = i.try(|i| LengthOrPercentage::parse(context, i)) {
                if compat_mode == CompatMode::Modern {
                    let _ = i.try(|i| i.expect_ident_matching("ellipse"));
                }
                y
            } else {
                if compat_mode == CompatMode::Modern {
                    i.expect_ident_matching("ellipse")?;
                }
                LengthOrPercentage::parse(context, i)?
            };
            Ok(GenericEndingShape::Ellipse(Ellipse::Radii(x.into(), y)))
        })
    }
}

impl ShapeExtent {
    fn parse_with_compat_mode(input: &mut Parser,
                              compat_mode: CompatMode)
                              -> Result<Self, ()> {
        match try!(Self::parse(input)) {
            ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == CompatMode::Modern => Err(()),
            keyword => Ok(keyword),
        }
    }
}

impl Parse for ColorStop {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        Ok(ColorStop {
            color: try!(CSSColor::parse(context, input)),
            position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(),
        })
    }
}

impl Parse for ImageRect {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        input.try(|i| i.expect_function_matching("-moz-image-rect"))?;
        input.parse_nested_block(|i| {
            let string = i.expect_url_or_string()?;
            let url = SpecifiedUrl::parse_from_string(string, context)?;
            i.expect_comma()?;
            let top = NumberOrPercentage::parse(context, i)?;
            i.expect_comma()?;
            let right = NumberOrPercentage::parse(context, i)?;
            i.expect_comma()?;
            let bottom = NumberOrPercentage::parse(context, i)?;
            i.expect_comma()?;
            let left = NumberOrPercentage::parse(context, i)?;

            Ok(ImageRect {
                url: url,
                top: top,
                right: right,
                bottom: bottom,
                left: left,
            })
        })
    }
}
<commit_msg>Reorganise specified::image::GradientItem methods<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/. */

//! CSS handling for the specified value of
//! [`image`][image]s
//!
//! [image]: https://drafts.csswg.org/css-images/#image-values

use Atom;
use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
#[cfg(feature = "servo")]
use servo_url::ServoUrl;
use std::f32::consts::PI;
use std::fmt;
use style_traits::ToCss;
use values::{Either, None_};
use values::generics::image::{Circle, CompatMode, Ellipse, ColorStop as GenericColorStop};
use values::generics::image::{EndingShape as GenericEndingShape, Gradient as GenericGradient};
use values::generics::image::{GradientItem as GenericGradientItem, GradientKind as GenericGradientKind};
use values::generics::image::{Image as GenericImage, ImageRect as GenericImageRect};
use values::generics::image::{LineDirection as GenericsLineDirection, ShapeExtent};
use values::specified::{Angle, CSSColor, Length, LengthOrPercentage, NumberOrPercentage, Percentage};
use values::specified::position::{Position, X, Y};
use values::specified::url::SpecifiedUrl;

/// A specified image layer.
pub type ImageLayer = Either<None_, Image>;

/// Specified values for an image according to CSS-IMAGES.
/// https://drafts.csswg.org/css-images/#image-values
pub type Image = GenericImage<Gradient, ImageRect>;

/// Specified values for a CSS gradient.
/// https://drafts.csswg.org/css-images/#gradients
pub type Gradient = GenericGradient<
    LineDirection,
    Length,
    LengthOrPercentage,
    Position,
    CSSColor,
>;

/// A specified gradient kind.
pub type GradientKind = GenericGradientKind<
    LineDirection,
    Length,
    LengthOrPercentage,
    Position,
>;

/// A specified gradient line direction.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum LineDirection {
    /// An angular direction.
    Angle(Angle),
    /// A horizontal direction.
    Horizontal(X),
    /// A vertical direction.
    Vertical(Y),
    /// A direction towards a corner of a box.
    Corner(X, Y),
}

/// A specified ending shape.
pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;

/// A specified gradient item.
pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>;

/// A computed color stop.
pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>;

/// Specified values for `moz-image-rect`
/// -moz-image-rect(<uri>, top, right, bottom, left);
pub type ImageRect = GenericImageRect<NumberOrPercentage>;

impl Parse for Image {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> {
        if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
            return Ok(GenericImage::Url(url));
        }
        if let Ok(gradient) = input.try(|i| Gradient::parse(context, i)) {
            return Ok(GenericImage::Gradient(gradient));
        }
        if let Ok(image_rect) = input.try(|input| ImageRect::parse(context, input)) {
            return Ok(GenericImage::Rect(image_rect));
        }

        Ok(GenericImage::Element(Image::parse_element(input)?))
    }
}

impl Image {
    /// Creates an already specified image value from an already resolved URL
    /// for insertion in the cascade.
    #[cfg(feature = "servo")]
    pub fn for_cascade(url: ServoUrl) -> Self {
        GenericImage::Url(SpecifiedUrl::for_cascade(url))
    }

    /// Parses a `-moz-element(# <element-id>)`.
    fn parse_element(input: &mut Parser) -> Result<Atom, ()> {
        input.try(|i| i.expect_function_matching("-moz-element"))?;
        input.parse_nested_block(|i| {
            match i.next()? {
                Token::IDHash(id) => Ok(Atom::from(id)),
                _ => Err(()),
            }
        })
    }
}

impl Parse for Gradient {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        enum Shape {
            Linear,
            Radial,
        }

        let (shape, repeating, compat_mode) = match_ignore_ascii_case! { &try!(input.expect_function()),
            "linear-gradient" => {
                (Shape::Linear, false, CompatMode::Modern)
            },
            "-webkit-linear-gradient" => {
                (Shape::Linear, false, CompatMode::WebKit)
            },
            "repeating-linear-gradient" => {
                (Shape::Linear, true, CompatMode::Modern)
            },
            "-webkit-repeating-linear-gradient" => {
                (Shape::Linear, true, CompatMode::WebKit)
            },
            "radial-gradient" => {
                (Shape::Radial, false, CompatMode::Modern)
            },
            "-webkit-radial-gradient" => {
                (Shape::Radial, false, CompatMode::WebKit)
            },
            "repeating-radial-gradient" => {
                (Shape::Radial, true, CompatMode::Modern)
            },
            "-webkit-repeating-radial-gradient" => {
                (Shape::Radial, true, CompatMode::WebKit)
            },
            _ => { return Err(()); }
        };

        let (kind, items) = input.parse_nested_block(|i| {
            let shape = match shape {
                Shape::Linear => GradientKind::parse_linear(context, i, compat_mode)?,
                Shape::Radial => GradientKind::parse_radial(context, i, compat_mode)?,
            };
            let items = GradientItem::parse_comma_separated(context, i)?;
            Ok((shape, items))
        })?;

        if items.len() < 2 {
            return Err(());
        }

        Ok(Gradient {
            items: items,
            repeating: repeating,
            kind: kind,
            compat_mode: compat_mode,
        })
    }
}

impl GradientKind {
    fn parse_linear(context: &ParserContext,
                    input: &mut Parser,
                    compat_mode: CompatMode)
                    -> Result<Self, ()> {
        let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode)) {
            input.expect_comma()?;
            d
        } else {
            LineDirection::Vertical(Y::Bottom)
        };
        Ok(GenericGradientKind::Linear(direction))
    }

    fn parse_radial(context: &ParserContext,
                    input: &mut Parser,
                    compat_mode: CompatMode)
                    -> Result<Self, ()> {
        let (shape, position) = if compat_mode == CompatMode::Modern {
            let shape = input.try(|i| EndingShape::parse(context, i, compat_mode));
            let position = input.try(|i| {
                i.expect_ident_matching("at")?;
                Position::parse(context, i)
            });
            (shape, position)
        } else {
            let position = input.try(|i| Position::parse(context, i));
            let shape = input.try(|i| {
                if position.is_ok() {
                    i.expect_comma()?;
                }
                EndingShape::parse(context, i, compat_mode)
            });
            (shape, position)
        };

        if shape.is_ok() || position.is_ok() {
            input.expect_comma()?;
        }

        let shape = shape.unwrap_or({
            GenericEndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner))
        });
        let position = position.unwrap_or(Position::center());
        Ok(GenericGradientKind::Radial(shape, position))
    }
}

impl GenericsLineDirection for LineDirection {
    fn points_downwards(&self) -> bool {
        match *self {
            LineDirection::Angle(ref angle) => angle.radians() == PI,
            LineDirection::Vertical(Y::Bottom) => true,
            _ => false,
        }
    }

    fn to_css<W>(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result
        where W: fmt::Write
    {
        match *self {
            LineDirection::Angle(angle) => {
                angle.to_css(dest)
            },
            LineDirection::Horizontal(x) => {
                if compat_mode == CompatMode::Modern {
                    dest.write_str("to ")?;
                }
                x.to_css(dest)
            },
            LineDirection::Vertical(y) => {
                if compat_mode == CompatMode::Modern {
                    dest.write_str("to ")?;
                }
                y.to_css(dest)
            },
            LineDirection::Corner(x, y) => {
                if compat_mode == CompatMode::Modern {
                    dest.write_str("to ")?;
                }
                x.to_css(dest)?;
                dest.write_str(" ")?;
                y.to_css(dest)
            }
        }
    }
}

impl LineDirection {
    fn parse(context: &ParserContext,
             input: &mut Parser,
             compat_mode: CompatMode)
             -> Result<Self, ()> {
        if let Ok(angle) = input.try(|i| Angle::parse_with_unitless(context, i)) {
            return Ok(LineDirection::Angle(angle));
        }
        input.try(|i| {
            if compat_mode == CompatMode::Modern {
                i.expect_ident_matching("to")?;
            }
            if let Ok(x) = i.try(X::parse) {
                if let Ok(y) = i.try(Y::parse) {
                    return Ok(LineDirection::Corner(x, y));
                }
                return Ok(LineDirection::Horizontal(x));
            }
            let y = Y::parse(i)?;
            if let Ok(x) = i.try(X::parse) {
                return Ok(LineDirection::Corner(x, y));
            }
            Ok(LineDirection::Vertical(y))
        })
    }
}

impl EndingShape {
    fn parse(context: &ParserContext,
             input: &mut Parser,
             compat_mode: CompatMode)
             -> Result<Self, ()> {
        if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
            if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
                return Ok(GenericEndingShape::Circle(Circle::Extent(extent)));
            }
            let _ = input.try(|i| i.expect_ident_matching("ellipse"));
            return Ok(GenericEndingShape::Ellipse(Ellipse::Extent(extent)));
        }
        if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
            if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
                return Ok(GenericEndingShape::Circle(Circle::Extent(extent)));
            }
            if compat_mode == CompatMode::Modern {
                if let Ok(length) = input.try(|i| Length::parse(context, i)) {
                    return Ok(GenericEndingShape::Circle(Circle::Radius(length)));
                }
            }
            return Ok(GenericEndingShape::Circle(Circle::Extent(ShapeExtent::FarthestCorner)));
        }
        if input.try(|i| i.expect_ident_matching("ellipse")).is_ok() {
            if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
                return Ok(GenericEndingShape::Ellipse(Ellipse::Extent(extent)));
            }
            if compat_mode == CompatMode::Modern {
                let pair: Result<_, ()> = input.try(|i| {
                    let x = LengthOrPercentage::parse(context, i)?;
                    let y = LengthOrPercentage::parse(context, i)?;
                    Ok((x, y))
                });
                if let Ok((x, y)) = pair {
                    return Ok(GenericEndingShape::Ellipse(Ellipse::Radii(x, y)));
                }
            }
            return Ok(GenericEndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)));
        }
        if let Ok(length) = input.try(|i| Length::parse(context, i)) {
            if let Ok(y) = input.try(|i| LengthOrPercentage::parse(context, i)) {
                if compat_mode == CompatMode::Modern {
                    let _ = input.try(|i| i.expect_ident_matching("ellipse"));
                }
                return Ok(GenericEndingShape::Ellipse(Ellipse::Radii(length.into(), y)));
            }
            if compat_mode == CompatMode::Modern {
                let y = input.try(|i| {
                    i.expect_ident_matching("ellipse")?;
                    LengthOrPercentage::parse(context, i)
                });
                if let Ok(y) = y {
                    return Ok(GenericEndingShape::Ellipse(Ellipse::Radii(length.into(), y)));
                }
                let _ = input.try(|i| i.expect_ident_matching("circle"));
            }
            return Ok(GenericEndingShape::Circle(Circle::Radius(length)));
        }
        input.try(|i| {
            let x = Percentage::parse(context, i)?;
            let y = if let Ok(y) = i.try(|i| LengthOrPercentage::parse(context, i)) {
                if compat_mode == CompatMode::Modern {
                    let _ = i.try(|i| i.expect_ident_matching("ellipse"));
                }
                y
            } else {
                if compat_mode == CompatMode::Modern {
                    i.expect_ident_matching("ellipse")?;
                }
                LengthOrPercentage::parse(context, i)?
            };
            Ok(GenericEndingShape::Ellipse(Ellipse::Radii(x.into(), y)))
        })
    }
}

impl ShapeExtent {
    fn parse_with_compat_mode(input: &mut Parser,
                              compat_mode: CompatMode)
                              -> Result<Self, ()> {
        match try!(Self::parse(input)) {
            ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == CompatMode::Modern => Err(()),
            keyword => Ok(keyword),
        }
    }
}

impl GradientItem {
    fn parse_comma_separated(context: &ParserContext, input: &mut Parser) -> Result<Vec<Self>, ()> {
        let mut seen_stop = false;
        let items = try!(input.parse_comma_separated(|input| {
            if seen_stop {
                if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) {
                    seen_stop = false;
                    return Ok(GenericGradientItem::InterpolationHint(hint));
                }
            }
            seen_stop = true;
            ColorStop::parse(context, input).map(GenericGradientItem::ColorStop)
        }));
        if !seen_stop || items.len() < 2 {
            return Err(());
        }
        Ok(items)
    }
}

impl Parse for ColorStop {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        Ok(ColorStop {
            color: try!(CSSColor::parse(context, input)),
            position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(),
        })
    }
}

impl Parse for ImageRect {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        input.try(|i| i.expect_function_matching("-moz-image-rect"))?;
        input.parse_nested_block(|i| {
            let string = i.expect_url_or_string()?;
            let url = SpecifiedUrl::parse_from_string(string, context)?;
            i.expect_comma()?;
            let top = NumberOrPercentage::parse(context, i)?;
            i.expect_comma()?;
            let right = NumberOrPercentage::parse(context, i)?;
            i.expect_comma()?;
            let bottom = NumberOrPercentage::parse(context, i)?;
            i.expect_comma()?;
            let left = NumberOrPercentage::parse(context, i)?;

            Ok(ImageRect {
                url: url,
                top: top,
                right: right,
                bottom: bottom,
                left: left,
            })
        })
    }
}
<|endoftext|>