<commit_before>use cpp_to_rust_common::errors::Result;
use cpp_to_rust_common::log;
use cpp_to_rust_common::utils::is_msvc;
use cpp_to_rust_common::file_utils::{PathBufWithAdded, repo_crate_local_path};
use cpp_to_rust_generator::config::Config;
use cpp_to_rust_common::cpp_build_config::CppBuildConfigData;
use cpp_to_rust_common::target;
use qt_generator_common::qmake_query::{get_installation_data, real_lib_name, lib_folder_name};
use std::path::PathBuf;

use doc_parser::DocParser;
use fix_header_names::fix_header_names;
use cpp_to_rust_generator::cpp_method::CppMethod;
use cpp_to_rust_generator::cpp_data::CppTypeKind;
use cpp_to_rust_generator::config::{CrateProperties, is_completed, completed_marker_path};
use doc_decoder::decode_doc;
use lib_configs;

pub fn exec_all(libs: Vec<String>,
                cache_dir: PathBuf,
                output_dir: PathBuf,
                no_local_paths: bool)
                -> Result<()> {
  let crate_templates_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
    .with_added("crate_templates");
  for sublib_name in libs {
    let lib_cache_dir = cache_dir.with_added(&sublib_name);
    let lib_crate_templates_path = crate_templates_path.with_added(&sublib_name);
    let lib_output_dir = output_dir.with_added(format!("qt_{}", sublib_name));

    let dependency_names = match sublib_name.as_str() {
      "core" => vec![],
      "gui" => vec!["core"],
      "widgets" => vec!["core", "gui"],
      _ => return Err(format!("Unknown lib name: {}", sublib_name).into()),
    };
    let mut dependency_paths = Vec::new();
    for dep in dependency_names {
      let path = cache_dir.with_added(dep);
      if !is_completed(&path) {
        return Err(format!("\"{}\" depends on \"{}\" but processing \
          in \"{}\" directory is not completed.",
                           sublib_name,
                           dep,
                           path.display())
          .into());
      }
      dependency_paths.push(path);
    }
    exec(&sublib_name,
         lib_cache_dir,
         lib_output_dir,
         lib_crate_templates_path,
         dependency_paths,
         no_local_paths)?;
  }
  Ok(())
}

fn exec(sublib_name: &str,
        cache_dir: PathBuf,
        output_dir: PathBuf,
        crate_templates_path: PathBuf,
        dependency_paths: Vec<PathBuf>,
        no_local_paths: bool)
        -> Result<()> {
  if is_completed(&cache_dir) {
    log::info("No processing! cpp_to_rust uses previous results.");
    log::info(format!("Remove \"{}\" file to force processing.", completed_marker_path(&cache_dir)));
    return Ok(());
  }
  log::info(format!("Processing library: {}", sublib_name));
  let qt_lib_name = real_lib_name(sublib_name);
  let mut crate_properties = CrateProperties::new(format!("qt_{}", sublib_name), "0.1.5");
  crate_properties.add_author("Pavel Strakhov <ri@idzaaus.org>");
  crate_properties.set_links_attribute(qt_lib_name.clone());
  crate_properties.remove_default_build_dependencies();
  crate_properties.add_build_dependency("qt_build_tools", "0.1", if no_local_paths {
    None
  } else {
    Some(repo_crate_local_path("qt_generator/qt_build_tools")?)
  });
  let mut config = Config::new(&output_dir, &cache_dir, crate_properties);
  let installation_data = get_installation_data(sublib_name)?;
  config.add_include_path(&installation_data.root_include_path);
  config.add_include_path(&installation_data.lib_include_path);
  config.add_target_include_path(&installation_data.lib_include_path);
  config.set_write_dependencies_local_paths(!no_local_paths);
  if no_local_paths {
    log::info("Local paths will not be written to the output crate. Make sure all dependencies \
               are published before trying to compile the crate.");
  } else {
    log::info("Output Cargo.toml file will contain local paths of used dependencies \
               (use --no-local-paths to disable).");
  }
  // TODO: does parsing work on MacOS without adding "-F"?

  config.add_include_directive(&lib_folder_name(sublib_name));
  config.add_cpp_data_filter(Box::new(move |cpp_data| {
    fix_header_names(cpp_data, &installation_data.lib_include_path)
  }));
  config.add_cpp_parser_flags(vec!["-fPIC", "-fcxx-exceptions"]);
  {
    let mut data = CppBuildConfigData::new();
    data.add_compiler_flags(vec!["-fPIC", "-std=gnu++11"]);
    config.cpp_build_config_mut().add(target::Condition::Env(target::Env::Msvc).negate(), data);
  }

  if is_msvc() {
    config.add_cpp_parser_flag("-std=c++14");
  } else {
    config.add_cpp_parser_flag("-std=gnu++11");
  }
  config.add_cpp_parser_blocked_name("qt_check_for_QGADGET_macro");
  let sublib_name_clone = sublib_name.to_string();
  config.add_cpp_data_filter(Box::new(move |cpp_data| {
    match decode_doc(&sublib_name_clone) {
      Ok(doc_data) => {
        let mut parser = DocParser::new(doc_data);
        find_methods_docs(&mut cpp_data.methods, &mut parser)?;
        for type1 in &mut cpp_data.types {
          match parser.doc_for_type(&type1.name) {
            Ok(doc) => {
              log::info(format!("Found doc for type: {}", type1.name));
              type1.doc = Some(doc.0);
              if let CppTypeKind::Enum { ref mut values } = type1.kind {
                for value in values {
                  if let Some(r) = doc.1.iter().find(|x| x.name == value.name) {
                    value.doc = Some(r.html.clone());
                  } else {
                    log::warning(format!("Not found doc for enum variant: {}::{}",
                                         type1.name,
                                         value.name));
                  }
                }
              }
            }
            Err(err) => {
              log::warning(format!("Not found doc for type: {}: {}", type1.name, err));
            }
          }
        }
      }
      Err(err) => {
        log::warning(format!("Failed to get Qt documentation: {}", err));
        err.discard_expected();
      }
    }
    Ok(())
  }));

  config.set_crate_template_path(crate_templates_path);
  match sublib_name {
    "core" => lib_configs::core(&mut config)?,
    "gui" => lib_configs::gui(&mut config)?,
    "widgets" => lib_configs::widgets(&mut config)?,
    _ => return Err(format!("Unknown lib name: {}", sublib_name).into()),
  }

  config.set_dependency_cache_paths(dependency_paths);
  config.exec()?;
  Ok(())
}

fn find_methods_docs(cpp_methods: &mut [CppMethod], data: &mut DocParser) -> Result<()> {
  for cpp_method in cpp_methods {
    if let Some(ref declaration_code) = cpp_method.declaration_code {
      match data.doc_for_method(&cpp_method.doc_id(),
                                declaration_code,
                                &cpp_method.short_text()) {
        Ok(doc) => cpp_method.doc = Some(doc),
        Err(msg) => {
          log::warning(format!("Failed to get documentation for method: {}: {}",
                               &cpp_method.short_text(),
                               msg));
        }
      }
    }
  }
  Ok(())
}
<commit_msg>fix build<commit_after>use cpp_to_rust_common::errors::Result;
use cpp_to_rust_common::log;
use cpp_to_rust_common::utils::is_msvc;
use cpp_to_rust_common::file_utils::{PathBufWithAdded, repo_crate_local_path};
use cpp_to_rust_generator::config::Config;
use cpp_to_rust_common::cpp_build_config::CppBuildConfigData;
use cpp_to_rust_common::target;
use qt_generator_common::qmake_query::{get_installation_data, real_lib_name, lib_folder_name};
use std::path::PathBuf;

use doc_parser::DocParser;
use fix_header_names::fix_header_names;
use cpp_to_rust_generator::cpp_method::CppMethod;
use cpp_to_rust_generator::cpp_data::CppTypeKind;
use cpp_to_rust_generator::config::{CrateProperties, is_completed, completed_marker_path};
use doc_decoder::decode_doc;
use lib_configs;

pub fn exec_all(libs: Vec<String>,
                cache_dir: PathBuf,
                output_dir: PathBuf,
                no_local_paths: bool)
                -> Result<()> {
  let crate_templates_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
    .with_added("crate_templates");
  for sublib_name in libs {
    let lib_cache_dir = cache_dir.with_added(&sublib_name);
    let lib_crate_templates_path = crate_templates_path.with_added(&sublib_name);
    let lib_output_dir = output_dir.with_added(format!("qt_{}", sublib_name));

    let dependency_names = match sublib_name.as_str() {
      "core" => vec![],
      "gui" => vec!["core"],
      "widgets" => vec!["core", "gui"],
      _ => return Err(format!("Unknown lib name: {}", sublib_name).into()),
    };
    let mut dependency_paths = Vec::new();
    for dep in dependency_names {
      let path = cache_dir.with_added(dep);
      if !is_completed(&path) {
        return Err(format!("\"{}\" depends on \"{}\" but processing \
          in \"{}\" directory is not completed.",
                           sublib_name,
                           dep,
                           path.display())
          .into());
      }
      dependency_paths.push(path);
    }
    exec(&sublib_name,
         lib_cache_dir,
         lib_output_dir,
         lib_crate_templates_path,
         dependency_paths,
         no_local_paths)?;
  }
  Ok(())
}

fn exec(sublib_name: &str,
        cache_dir: PathBuf,
        output_dir: PathBuf,
        crate_templates_path: PathBuf,
        dependency_paths: Vec<PathBuf>,
        no_local_paths: bool)
        -> Result<()> {
  if is_completed(&cache_dir) {
    log::info("No processing! cpp_to_rust uses previous results.");
    log::info(format!("Remove \"{}\" file to force processing.", completed_marker_path(&cache_dir).display()));
    return Ok(());
  }
  log::info(format!("Processing library: {}", sublib_name));
  let qt_lib_name = real_lib_name(sublib_name);
  let mut crate_properties = CrateProperties::new(format!("qt_{}", sublib_name), "0.1.5");
  crate_properties.add_author("Pavel Strakhov <ri@idzaaus.org>");
  crate_properties.set_links_attribute(qt_lib_name.clone());
  crate_properties.remove_default_build_dependencies();
  crate_properties.add_build_dependency("qt_build_tools", "0.1", if no_local_paths {
    None
  } else {
    Some(repo_crate_local_path("qt_generator/qt_build_tools")?)
  });
  let mut config = Config::new(&output_dir, &cache_dir, crate_properties);
  let installation_data = get_installation_data(sublib_name)?;
  config.add_include_path(&installation_data.root_include_path);
  config.add_include_path(&installation_data.lib_include_path);
  config.add_target_include_path(&installation_data.lib_include_path);
  config.set_write_dependencies_local_paths(!no_local_paths);
  if no_local_paths {
    log::info("Local paths will not be written to the output crate. Make sure all dependencies \
               are published before trying to compile the crate.");
  } else {
    log::info("Output Cargo.toml file will contain local paths of used dependencies \
               (use --no-local-paths to disable).");
  }
  // TODO: does parsing work on MacOS without adding "-F"?

  config.add_include_directive(&lib_folder_name(sublib_name));
  config.add_cpp_data_filter(Box::new(move |cpp_data| {
    fix_header_names(cpp_data, &installation_data.lib_include_path)
  }));
  config.add_cpp_parser_flags(vec!["-fPIC", "-fcxx-exceptions"]);
  {
    let mut data = CppBuildConfigData::new();
    data.add_compiler_flags(vec!["-fPIC", "-std=gnu++11"]);
    config.cpp_build_config_mut().add(target::Condition::Env(target::Env::Msvc).negate(), data);
  }

  if is_msvc() {
    config.add_cpp_parser_flag("-std=c++14");
  } else {
    config.add_cpp_parser_flag("-std=gnu++11");
  }
  config.add_cpp_parser_blocked_name("qt_check_for_QGADGET_macro");
  let sublib_name_clone = sublib_name.to_string();
  config.add_cpp_data_filter(Box::new(move |cpp_data| {
    match decode_doc(&sublib_name_clone) {
      Ok(doc_data) => {
        let mut parser = DocParser::new(doc_data);
        find_methods_docs(&mut cpp_data.methods, &mut parser)?;
        for type1 in &mut cpp_data.types {
          match parser.doc_for_type(&type1.name) {
            Ok(doc) => {
              log::info(format!("Found doc for type: {}", type1.name));
              type1.doc = Some(doc.0);
              if let CppTypeKind::Enum { ref mut values } = type1.kind {
                for value in values {
                  if let Some(r) = doc.1.iter().find(|x| x.name == value.name) {
                    value.doc = Some(r.html.clone());
                  } else {
                    log::warning(format!("Not found doc for enum variant: {}::{}",
                                         type1.name,
                                         value.name));
                  }
                }
              }
            }
            Err(err) => {
              log::warning(format!("Not found doc for type: {}: {}", type1.name, err));
            }
          }
        }
      }
      Err(err) => {
        log::warning(format!("Failed to get Qt documentation: {}", err));
        err.discard_expected();
      }
    }
    Ok(())
  }));

  config.set_crate_template_path(crate_templates_path);
  match sublib_name {
    "core" => lib_configs::core(&mut config)?,
    "gui" => lib_configs::gui(&mut config)?,
    "widgets" => lib_configs::widgets(&mut config)?,
    _ => return Err(format!("Unknown lib name: {}", sublib_name).into()),
  }

  config.set_dependency_cache_paths(dependency_paths);
  config.exec()?;
  Ok(())
}

fn find_methods_docs(cpp_methods: &mut [CppMethod], data: &mut DocParser) -> Result<()> {
  for cpp_method in cpp_methods {
    if let Some(ref declaration_code) = cpp_method.declaration_code {
      match data.doc_for_method(&cpp_method.doc_id(),
                                declaration_code,
                                &cpp_method.short_text()) {
        Ok(doc) => cpp_method.doc = Some(doc),
        Err(msg) => {
          log::warning(format!("Failed to get documentation for method: {}: {}",
                               &cpp_method.short_text(),
                               msg));
        }
      }
    }
  }
  Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate askama;
#[macro_use]
extern crate criterion;

use askama::Template;
use criterion::Criterion;

criterion_main!(benches);
criterion_group!(benches, functions);

fn functions(c: &mut Criterion) {
    c.bench_function("Big table", |b| big_table(b, &100));
    c.bench_function("Teams", |b| teams(b));
}

fn big_table(b: &mut criterion::Bencher, size: &usize) {
    let mut table = Vec::with_capacity(*size);
    for _ in 0..*size {
        let mut inner = Vec::with_capacity(*size);
        for i in 0..*size {
            inner.push(i);
        }
        table.push(inner);
    }
    let ctx = BigTable { table };
    b.iter(|| ctx.render().unwrap());
}

#[derive(Template)]
#[template(path = "big-table.html")]
struct BigTable {
    table: Vec<Vec<usize>>,
}

fn teams(b: &mut criterion::Bencher) {
    let teams = Teams {
        year: 2015,
        teams: vec![
            Team {
                name: "Jiangsu".into(),
                score: 43,
            },
            Team {
                name: "Beijing".into(),
                score: 27,
            },
            Team {
                name: "Guangzhou".into(),
                score: 22,
            },
            Team {
                name: "Shandong".into(),
                score: 12,
            },
        ],
    };
    b.iter(|| teams.render().unwrap());
}

#[derive(Template)]
#[template(path = "teams.html")]
struct Teams {
    year: u16,
    teams: Vec<Team>,
}

struct Team {
    name: String,
    score: u8,
}
<commit_msg>Remove unused #[macro_use] attribute<commit_after>extern crate askama;
#[macro_use]
extern crate criterion;

use askama::Template;
use criterion::Criterion;

criterion_main!(benches);
criterion_group!(benches, functions);

fn functions(c: &mut Criterion) {
    c.bench_function("Big table", |b| big_table(b, &100));
    c.bench_function("Teams", |b| teams(b));
}

fn big_table(b: &mut criterion::Bencher, size: &usize) {
    let mut table = Vec::with_capacity(*size);
    for _ in 0..*size {
        let mut inner = Vec::with_capacity(*size);
        for i in 0..*size {
            inner.push(i);
        }
        table.push(inner);
    }
    let ctx = BigTable { table };
    b.iter(|| ctx.render().unwrap());
}

#[derive(Template)]
#[template(path = "big-table.html")]
struct BigTable {
    table: Vec<Vec<usize>>,
}

fn teams(b: &mut criterion::Bencher) {
    let teams = Teams {
        year: 2015,
        teams: vec![
            Team {
                name: "Jiangsu".into(),
                score: 43,
            },
            Team {
                name: "Beijing".into(),
                score: 27,
            },
            Team {
                name: "Guangzhou".into(),
                score: 22,
            },
            Team {
                name: "Shandong".into(),
                score: 12,
            },
        ],
    };
    b.iter(|| teams.render().unwrap());
}

#[derive(Template)]
#[template(path = "teams.html")]
struct Teams {
    year: u16,
    teams: Vec<Team>,
}

struct Team {
    name: String,
    score: u8,
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::sync::Arc;

use common::{
    Diagnostic, DiagnosticsResult, FeatureFlag, Location, Named, NamedItem, WithLocation,
};
use graphql_ir::{
    associated_data_impl, transform_list, Directive, FragmentDefinition, FragmentSpread,
    InlineFragment, LinkedField, OperationDefinition, Program, Selection, Transformed,
    TransformedValue, Transformer,
};
use intern::string_key::{Intern, StringKey};
use lazy_static::lazy_static;
use schema::{Schema, Type};

use crate::ValidationMessage;

lazy_static! {
    pub static ref FRAGMENT_ALIAS_DIRECTIVE_NAME: StringKey = "alias".intern();
    pub static ref FRAGMENT_ALIAS_ARGUMENT_NAME: StringKey = "as".intern();
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FragmentAliasMetadata {
    pub alias: WithLocation<StringKey>,
    pub type_condition: Option<Type>,
    pub selection_type: Type,
}
associated_data_impl!(FragmentAliasMetadata);

pub fn fragment_alias_directive(
    program: &Program,
    feature_flag: &FeatureFlag,
) -> DiagnosticsResult<Program> {
    let mut transform = FragmentAliasTransform::new(program, feature_flag);
    let next_program = transform
        .transform_program(program)
        .replace_or_else(|| program.clone());
    if transform.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transform.errors)
    }
}

struct FragmentAliasTransform<'program> {
    program: &'program Program,
    feature_flag: &'program FeatureFlag,
    document_name: Option<StringKey>,
    parent_type: Option<Type>,
    errors: Vec<Diagnostic>,
}

impl<'program> FragmentAliasTransform<'program> {
    fn new(program: &'program Program, feature_flag: &'program FeatureFlag) -> Self {
        Self {
            program,
            feature_flag,
            document_name: None,
            parent_type: None,
            errors: Vec::new(),
        }
    }

    fn transform_alias_directives<N>(
        &mut self,
        directives: &[Directive],
        type_condition: Option<Type>,
        get_default_name: N,
    ) -> TransformedValue<Vec<Directive>>
    where
        N: Fn() -> Option<StringKey>,
    {
        transform_list(directives, |directive| {
            if directive.name() != *FRAGMENT_ALIAS_DIRECTIVE_NAME {
                return Transformed::Keep;
            }

            let allowed = match self.document_name {
                Some(name) => self.feature_flag.is_enabled_for(name),
                None => false,
            };

            if !allowed {
                self.errors.push(Diagnostic::error(
                    ValidationMessage::FragmentAliasDirectiveDisabled,
                    directive.name.location,
                ));
                return Transformed::Keep;
            }
            let alias = match directive.arguments.named(*FRAGMENT_ALIAS_ARGUMENT_NAME) {
                Some(arg) => match arg.value.item.get_string_literal() {
                    Some(name) => WithLocation::new(arg.name.location, name),
                    None => {
                        self.errors.push(Diagnostic::error(
                            ValidationMessage::FragmentAliasDirectiveDynamicNameArg,
                            arg.value.location,
                        ));
                        return Transformed::Keep;
                    }
                },
                None => match get_default_name() {
                    None => {
                        self.errors.push(Diagnostic::error(
                            ValidationMessage::FragmentAliasDirectiveMissingAs,
                            directive.name.location,
                        ));
                        return Transformed::Keep;
                    }
                    Some(as_) => WithLocation::new(directive.name.location, as_),
                },
            };

            // In the future we might want to relax this restriction, but for now this allows us
            // to avoid having to consider how @alias would interact
            // with all other directives like @defer.
            if directives.len() > 1 {
                self.errors.push(Diagnostic::error(
                    ValidationMessage::FragmentAliasIncompatibleDirective,
                    directive.name.location,
                ));
                return Transformed::Keep;
            }
            Transformed::Replace(
                FragmentAliasMetadata {
                    alias,
                    type_condition,
                    selection_type:
                        type_condition.unwrap_or(
                            self.parent_type
                                .expect("Selection should be within a parent type."),
                        ),
                }
                .into(),
            )
        })
    }
}

impl Transformer for FragmentAliasTransform<'_> {
    const NAME: &'static str = "NamedFragmentSpreadsTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        self.document_name = Some(fragment.name.item);
        self.parent_type = Some(fragment.type_condition);
        let transformed = self.default_transform_fragment(fragment);
        self.parent_type = None;
        self.document_name = None;
        transformed
    }

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        self.document_name = Some(operation.name.item);
        self.parent_type = Some(operation.type_);
        let transformed = self.default_transform_operation(operation);
        self.parent_type = None;
        self.document_name = None;
        transformed
    }

    fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
        let get_default_name = || {
            fragment
                .type_condition
                .map(|type_| self.program.schema.get_type_name(type_))
        };
        let previous_parent_type = self.parent_type;

        if let Some(type_condition) = fragment.type_condition {
            self.parent_type = Some(type_condition);
        }

        let transformed = match self.transform_alias_directives(
            &fragment.directives,
            fragment.type_condition,
            get_default_name,
        ) {
            TransformedValue::Keep => self.default_transform_inline_fragment(fragment),
            TransformedValue::Replace(next_directives) => {
                Transformed::Replace(Selection::InlineFragment(Arc::new(InlineFragment {
                    directives: next_directives,
                    type_condition: fragment.type_condition,
                    selections: self
                        .transform_selections(&fragment.selections)
                        .replace_or_else(|| fragment.selections.clone()),
                    spread_location: Location::generated(),
                })))
            }
        };

        self.parent_type = previous_parent_type;

        transformed
    }

    fn transform_fragment_spread(&mut self, spread: &FragmentSpread) -> Transformed<Selection> {
        let type_condition = Some(
            self.program
                .fragment(spread.fragment.item)
                .expect("I believe we have already validated that all fragments exist")
                .type_condition,
        );
        let get_default_name = || Some(spread.fragment.item);
        self.transform_alias_directives(&spread.directives, type_condition, get_default_name)
            .map(|directives| {
                Selection::FragmentSpread(Arc::new(FragmentSpread {
                    fragment: spread.fragment,
                    arguments: spread.arguments.clone(),
                    directives,
                }))
            })
            .into()
    }

    fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed<Selection> {
        let previous_parent_type = self.parent_type;

        self.parent_type = Some(
            self.program
                .schema
                .field(field.definition.item)
                .type_
                .inner(),
        );

        let transformed = self.default_transform_linked_field(field);

        self.parent_type = previous_parent_type;

        transformed
    }
}
<commit_msg>Update rustfmt and reformat the repo back<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::sync::Arc;

use common::{
    Diagnostic, DiagnosticsResult, FeatureFlag, Location, Named, NamedItem, WithLocation,
};
use graphql_ir::{
    associated_data_impl, transform_list, Directive, FragmentDefinition, FragmentSpread,
    InlineFragment, LinkedField, OperationDefinition, Program, Selection, Transformed,
    TransformedValue, Transformer,
};
use intern::string_key::{Intern, StringKey};
use lazy_static::lazy_static;
use schema::{Schema, Type};

use crate::ValidationMessage;

lazy_static! {
    pub static ref FRAGMENT_ALIAS_DIRECTIVE_NAME: StringKey = "alias".intern();
    pub static ref FRAGMENT_ALIAS_ARGUMENT_NAME: StringKey = "as".intern();
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FragmentAliasMetadata {
    pub alias: WithLocation<StringKey>,
    pub type_condition: Option<Type>,
    pub selection_type: Type,
}
associated_data_impl!(FragmentAliasMetadata);

pub fn fragment_alias_directive(
    program: &Program,
    feature_flag: &FeatureFlag,
) -> DiagnosticsResult<Program> {
    let mut transform = FragmentAliasTransform::new(program, feature_flag);
    let next_program = transform
        .transform_program(program)
        .replace_or_else(|| program.clone());
    if transform.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transform.errors)
    }
}

struct FragmentAliasTransform<'program> {
    program: &'program Program,
    feature_flag: &'program FeatureFlag,
    document_name: Option<StringKey>,
    parent_type: Option<Type>,
    errors: Vec<Diagnostic>,
}

impl<'program> FragmentAliasTransform<'program> {
    fn new(program: &'program Program, feature_flag: &'program FeatureFlag) -> Self {
        Self {
            program,
            feature_flag,
            document_name: None,
            parent_type: None,
            errors: Vec::new(),
        }
    }

    fn transform_alias_directives<N>(
        &mut self,
        directives: &[Directive],
        type_condition: Option<Type>,
        get_default_name: N,
    ) -> TransformedValue<Vec<Directive>>
    where
        N: Fn() -> Option<StringKey>,
    {
        transform_list(directives, |directive| {
            if directive.name() != *FRAGMENT_ALIAS_DIRECTIVE_NAME {
                return Transformed::Keep;
            }

            let allowed = match self.document_name {
                Some(name) => self.feature_flag.is_enabled_for(name),
                None => false,
            };

            if !allowed {
                self.errors.push(Diagnostic::error(
                    ValidationMessage::FragmentAliasDirectiveDisabled,
                    directive.name.location,
                ));
                return Transformed::Keep;
            }
            let alias = match directive.arguments.named(*FRAGMENT_ALIAS_ARGUMENT_NAME) {
                Some(arg) => match arg.value.item.get_string_literal() {
                    Some(name) => WithLocation::new(arg.name.location, name),
                    None => {
                        self.errors.push(Diagnostic::error(
                            ValidationMessage::FragmentAliasDirectiveDynamicNameArg,
                            arg.value.location,
                        ));
                        return Transformed::Keep;
                    }
                },
                None => match get_default_name() {
                    None => {
                        self.errors.push(Diagnostic::error(
                            ValidationMessage::FragmentAliasDirectiveMissingAs,
                            directive.name.location,
                        ));
                        return Transformed::Keep;
                    }
                    Some(as_) => WithLocation::new(directive.name.location, as_),
                },
            };

            // In the future we might want to relax this restriction, but for now this allows us
            // to avoid having to consider how @alias would interact
            // with all other directives like @defer.
            if directives.len() > 1 {
                self.errors.push(Diagnostic::error(
                    ValidationMessage::FragmentAliasIncompatibleDirective,
                    directive.name.location,
                ));
                return Transformed::Keep;
            }
            Transformed::Replace(
                FragmentAliasMetadata {
                    alias,
                    type_condition,
                    selection_type: type_condition.unwrap_or(
                        self.parent_type
                            .expect("Selection should be within a parent type."),
                    ),
                }
                .into(),
            )
        })
    }
}

impl Transformer for FragmentAliasTransform<'_> {
    const NAME: &'static str = "NamedFragmentSpreadsTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        self.document_name = Some(fragment.name.item);
        self.parent_type = Some(fragment.type_condition);
        let transformed = self.default_transform_fragment(fragment);
        self.parent_type = None;
        self.document_name = None;
        transformed
    }

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        self.document_name = Some(operation.name.item);
        self.parent_type = Some(operation.type_);
        let transformed = self.default_transform_operation(operation);
        self.parent_type = None;
        self.document_name = None;
        transformed
    }

    fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
        let get_default_name = || {
            fragment
                .type_condition
                .map(|type_| self.program.schema.get_type_name(type_))
        };
        let previous_parent_type = self.parent_type;

        if let Some(type_condition) = fragment.type_condition {
            self.parent_type = Some(type_condition);
        }

        let transformed = match self.transform_alias_directives(
            &fragment.directives,
            fragment.type_condition,
            get_default_name,
        ) {
            TransformedValue::Keep => self.default_transform_inline_fragment(fragment),
            TransformedValue::Replace(next_directives) => {
                Transformed::Replace(Selection::InlineFragment(Arc::new(InlineFragment {
                    directives: next_directives,
                    type_condition: fragment.type_condition,
                    selections: self
                        .transform_selections(&fragment.selections)
                        .replace_or_else(|| fragment.selections.clone()),
                    spread_location: Location::generated(),
                })))
            }
        };

        self.parent_type = previous_parent_type;

        transformed
    }

    fn transform_fragment_spread(&mut self, spread: &FragmentSpread) -> Transformed<Selection> {
        let type_condition = Some(
            self.program
                .fragment(spread.fragment.item)
                .expect("I believe we have already validated that all fragments exist")
                .type_condition,
        );
        let get_default_name = || Some(spread.fragment.item);
        self.transform_alias_directives(&spread.directives, type_condition, get_default_name)
            .map(|directives| {
                Selection::FragmentSpread(Arc::new(FragmentSpread {
                    fragment: spread.fragment,
                    arguments: spread.arguments.clone(),
                    directives,
                }))
            })
            .into()
    }

    fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed<Selection> {
        let previous_parent_type = self.parent_type;

        self.parent_type = Some(
            self.program
                .schema
                .field(field.definition.item)
                .type_
                .inner(),
        );

        let transformed = self.default_transform_linked_field(field);

        self.parent_type = previous_parent_type;

        transformed
    }
}
<|endoftext|>


<commit_before>//! Propagate `Qualif`s between locals and query the results.
//!
//! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs.

use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::JoinSemiLattice;
use rustc_span::DUMMY_SP;

use std::fmt;
use std::marker::PhantomData;

use super::{qualifs, ConstCx, Qualif};

/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
/// `FlowSensitiveAnalysis`.
///
/// To account for indirect assignments, data flow conservatively assumes that local becomes
/// qualified immediately after it is borrowed or its address escapes. The borrow must allow for
/// mutation, which includes shared borrows of places with interior mutability. The type of
/// borrowed place must contain the qualif.
struct TransferFunction<'a, 'mir, 'tcx, Q> {
    ccx: &'a ConstCx<'mir, 'tcx>,
    state: &'a mut State,
    _qualif: PhantomData<Q>,
}

impl<Q> TransferFunction<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self {
        TransferFunction { ccx, state, _qualif: PhantomData }
    }

    fn initialize_state(&mut self) {
        self.state.qualif.clear();
        self.state.borrow.clear();

        for arg in self.ccx.body.args_iter() {
            let arg_ty = self.ccx.body.local_decls[arg].ty;
            if Q::in_any_value_of_ty(self.ccx, arg_ty) {
                self.state.qualif.insert(arg);
            }
        }
    }

    fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) {
        debug_assert!(!place.is_indirect());

        if !value {
            for (base, _elem) in place.iter_projections() {
                let base_ty = base.ty(self.ccx.body, self.ccx.tcx);
                if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) {
                    value = true;
                    break;
                }
            }
        }

        match (value, place.as_ref()) {
            (true, mir::PlaceRef { local, .. }) => {
                self.state.qualif.insert(local);
            }

            // For now, we do not clear the qualif if a local is overwritten in full by
            // an unqualified rvalue (e.g. `y = 5`). This is to be consistent
            // with aggregates where we overwrite all fields with assignments, which would not
            // get this feature.
            (false, mir::PlaceRef { local: _, projection: &[] }) => {
                // self.state.qualif.remove(*local);
            }

            _ => {}
        }
    }

    fn apply_call_return_effect(
        &mut self,
        _block: BasicBlock,
        _func: &mir::Operand<'tcx>,
        _args: &[mir::Operand<'tcx>],
        return_place: mir::Place<'tcx>,
    ) {
        // We cannot reason about another function's internals, so use conservative type-based
        // qualification for the result of a function call.
        let return_ty = return_place.ty(self.ccx.body, self.ccx.tcx).ty;
        let qualif = Q::in_any_value_of_ty(self.ccx, return_ty);

        if !return_place.is_indirect() {
            self.assign_qualif_direct(&return_place, qualif);
        }
    }

    fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
        // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
        // it might allow mutation until resolution of #56604.
        true
    }

    fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
        match kind {
            mir::BorrowKind::Mut { .. } => true,
            mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
                self.shared_borrow_allows_mutation(place)
            }
        }
    }

    /// `&` only allow mutation if the borrowed place is `!Freeze`.
    ///
    /// This assumes that it is UB to take the address of a struct field whose type is
    /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
    /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
    /// have to check the type of the borrowed **local** instead of the borrowed **place**
    /// below. See [rust-lang/unsafe-code-guidelines#134].
    ///
    /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
    fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
        !place
            .ty(self.ccx.body, self.ccx.tcx)
            .ty
            .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
    }
}

impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
        self.super_operand(operand, location);

        if !Q::IS_CLEARED_ON_MOVE {
            return;
        }

        // If a local with no projections is moved from (e.g. `x` in `y = x`), record that
        // it no longer needs to be dropped.
        if let mir::Operand::Move(place) = operand {
            if let Some(local) = place.as_local() {
                // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
                // implementation we retain qualif if a local had been borrowed before. This might
                // not be strictly necessary since the local is no longer initialized.
                if !self.state.borrow.contains(local) {
                    self.state.qualif.remove(local);
                }
            }
        }
    }

    fn visit_assign(
        &mut self,
        place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: Location,
    ) {
        let qualif =
            qualifs::in_rvalue::<Q, _>(self.ccx, &mut |l| self.state.qualif.contains(l), rvalue);
        if !place.is_indirect() {
            self.assign_qualif_direct(place, qualif);
        }

        // We need to assign qualifs to the left-hand side before visiting `rvalue` since
        // qualifs can be cleared on move.
        self.super_assign(place, rvalue, location);
    }

    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
        self.super_rvalue(rvalue, location);

        match rvalue {
            mir::Rvalue::AddressOf(mt, borrowed_place) => {
                if !borrowed_place.is_indirect()
                    && self.address_of_allows_mutation(*mt, *borrowed_place)
                {
                    let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
                    if Q::in_any_value_of_ty(self.ccx, place_ty) {
                        self.state.qualif.insert(borrowed_place.local);
                        self.state.borrow.insert(borrowed_place.local);
                    }
                }
            }

            mir::Rvalue::Ref(_, kind, borrowed_place) => {
                if !borrowed_place.is_indirect() && self.ref_allows_mutation(*kind, *borrowed_place)
                {
                    let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
                    if Q::in_any_value_of_ty(self.ccx, place_ty) {
                        self.state.qualif.insert(borrowed_place.local);
                        self.state.borrow.insert(borrowed_place.local);
                    }
                }
            }

            mir::Rvalue::Cast(..)
            | mir::Rvalue::ShallowInitBox(..)
            | mir::Rvalue::Use(..)
            | mir::Rvalue::ThreadLocalRef(..)
            | mir::Rvalue::Repeat(..)
            | mir::Rvalue::Len(..)
            | mir::Rvalue::BinaryOp(..)
            | mir::Rvalue::CheckedBinaryOp(..)
            | mir::Rvalue::NullaryOp(..)
            | mir::Rvalue::UnaryOp(..)
            | mir::Rvalue::Discriminant(..)
            | mir::Rvalue::Aggregate(..) => {}
        }
    }

    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
        match statement.kind {
            StatementKind::StorageDead(local) => {
                self.state.qualif.remove(local);
                self.state.borrow.remove(local);
            }
            _ => self.super_statement(statement, location),
        }
    }

    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
        // The effect of assignment to the return place in `TerminatorKind::Call` is not applied
        // here; that occurs in `apply_call_return_effect`.

        if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
            let qualif = qualifs::in_operand::<Q, _>(
                self.ccx,
                &mut |l| self.state.qualif.contains(l),
                value,
            );

            if !place.is_indirect() {
                self.assign_qualif_direct(place, qualif);
            }
        }

        // We ignore borrow on drop because custom drop impls are not allowed in consts.
        // FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.

        // We need to assign qualifs to the dropped location before visiting the operand that
        // replaces it since qualifs can be cleared on move.
        self.super_terminator(terminator, location);
    }
}

/// The dataflow analysis used to propagate qualifs on arbitrary CFGs.
pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> {
    ccx: &'a ConstCx<'mir, 'tcx>,
    _qualif: PhantomData<Q>,
}

impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    pub(super) fn new(_: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self {
        FlowSensitiveAnalysis { ccx, _qualif: PhantomData }
    }

    fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> {
        TransferFunction::<Q>::new(self.ccx, state)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(super) struct State {
    /// Describes whether a local contains qualif.
    pub qualif: BitSet<Local>,
    /// Describes whether a local's address escaped and it might become qualified as a result an
    /// indirect mutation.
    pub borrow: BitSet<Local>,
}

impl State {
    #[inline]
    pub(super) fn contains(&self, local: Local) -> bool {
        self.qualif.contains(local)
    }
}

impl<C> DebugWithContext<C> for State {
    fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("qualif: ")?;
        self.qualif.fmt_with(ctxt, f)?;
        f.write_str(" borrow: ")?;
        self.borrow.fmt_with(ctxt, f)?;
        Ok(())
    }

    fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self == old {
            return Ok(());
        }

        if self.qualif != old.qualif {
            f.write_str("qualif: ")?;
            self.qualif.fmt_diff_with(&old.qualif, ctxt, f)?;
            f.write_str("\n")?;
        }

        if self.borrow != old.borrow {
            f.write_str("borrow: ")?;
            self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?;
            f.write_str("\n")?;
        }

        Ok(())
    }
}

impl JoinSemiLattice for State {
    fn join(&mut self, other: &Self) -> bool {
        self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow)
    }
}

impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    type Domain = State;

    const NAME: &'static str = Q::ANALYSIS_NAME;

    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
        State {
            qualif: BitSet::new_empty(body.local_decls.len()),
            borrow: BitSet::new_empty(body.local_decls.len()),
        }
    }

    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
        self.transfer_function(state).initialize_state();
    }
}

impl<Q> rustc_mir_dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    fn apply_statement_effect(
        &self,
        state: &mut Self::Domain,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        self.transfer_function(state).visit_statement(statement, location);
    }

    fn apply_terminator_effect(
        &self,
        state: &mut Self::Domain,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    ) {
        self.transfer_function(state).visit_terminator(terminator, location);
    }

    fn apply_call_return_effect(
        &self,
        state: &mut Self::Domain,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: mir::Place<'tcx>,
    ) {
        self.transfer_function(state).apply_call_return_effect(block, func, args, return_place)
    }
}
<commit_msg>Auto merge of #90535 - tmiasko:clone-from, r=oli-obk<commit_after>//! Propagate `Qualif`s between locals and query the results.
//!
//! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs.

use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::JoinSemiLattice;
use rustc_span::DUMMY_SP;

use std::fmt;
use std::marker::PhantomData;

use super::{qualifs, ConstCx, Qualif};

/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
/// `FlowSensitiveAnalysis`.
///
/// To account for indirect assignments, data flow conservatively assumes that local becomes
/// qualified immediately after it is borrowed or its address escapes. The borrow must allow for
/// mutation, which includes shared borrows of places with interior mutability. The type of
/// borrowed place must contain the qualif.
struct TransferFunction<'a, 'mir, 'tcx, Q> {
    ccx: &'a ConstCx<'mir, 'tcx>,
    state: &'a mut State,
    _qualif: PhantomData<Q>,
}

impl<Q> TransferFunction<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self {
        TransferFunction { ccx, state, _qualif: PhantomData }
    }

    fn initialize_state(&mut self) {
        self.state.qualif.clear();
        self.state.borrow.clear();

        for arg in self.ccx.body.args_iter() {
            let arg_ty = self.ccx.body.local_decls[arg].ty;
            if Q::in_any_value_of_ty(self.ccx, arg_ty) {
                self.state.qualif.insert(arg);
            }
        }
    }

    fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) {
        debug_assert!(!place.is_indirect());

        if !value {
            for (base, _elem) in place.iter_projections() {
                let base_ty = base.ty(self.ccx.body, self.ccx.tcx);
                if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) {
                    value = true;
                    break;
                }
            }
        }

        match (value, place.as_ref()) {
            (true, mir::PlaceRef { local, .. }) => {
                self.state.qualif.insert(local);
            }

            // For now, we do not clear the qualif if a local is overwritten in full by
            // an unqualified rvalue (e.g. `y = 5`). This is to be consistent
            // with aggregates where we overwrite all fields with assignments, which would not
            // get this feature.
            (false, mir::PlaceRef { local: _, projection: &[] }) => {
                // self.state.qualif.remove(*local);
            }

            _ => {}
        }
    }

    fn apply_call_return_effect(
        &mut self,
        _block: BasicBlock,
        _func: &mir::Operand<'tcx>,
        _args: &[mir::Operand<'tcx>],
        return_place: mir::Place<'tcx>,
    ) {
        // We cannot reason about another function's internals, so use conservative type-based
        // qualification for the result of a function call.
        let return_ty = return_place.ty(self.ccx.body, self.ccx.tcx).ty;
        let qualif = Q::in_any_value_of_ty(self.ccx, return_ty);

        if !return_place.is_indirect() {
            self.assign_qualif_direct(&return_place, qualif);
        }
    }

    fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
        // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
        // it might allow mutation until resolution of #56604.
        true
    }

    fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
        match kind {
            mir::BorrowKind::Mut { .. } => true,
            mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
                self.shared_borrow_allows_mutation(place)
            }
        }
    }

    /// `&` only allow mutation if the borrowed place is `!Freeze`.
    ///
    /// This assumes that it is UB to take the address of a struct field whose type is
    /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
    /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
    /// have to check the type of the borrowed **local** instead of the borrowed **place**
    /// below. See [rust-lang/unsafe-code-guidelines#134].
    ///
    /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
    fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
        !place
            .ty(self.ccx.body, self.ccx.tcx)
            .ty
            .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
    }
}

impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
        self.super_operand(operand, location);

        if !Q::IS_CLEARED_ON_MOVE {
            return;
        }

        // If a local with no projections is moved from (e.g. `x` in `y = x`), record that
        // it no longer needs to be dropped.
        if let mir::Operand::Move(place) = operand {
            if let Some(local) = place.as_local() {
                // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
                // implementation we retain qualif if a local had been borrowed before. This might
                // not be strictly necessary since the local is no longer initialized.
                if !self.state.borrow.contains(local) {
                    self.state.qualif.remove(local);
                }
            }
        }
    }

    fn visit_assign(
        &mut self,
        place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: Location,
    ) {
        let qualif =
            qualifs::in_rvalue::<Q, _>(self.ccx, &mut |l| self.state.qualif.contains(l), rvalue);
        if !place.is_indirect() {
            self.assign_qualif_direct(place, qualif);
        }

        // We need to assign qualifs to the left-hand side before visiting `rvalue` since
        // qualifs can be cleared on move.
        self.super_assign(place, rvalue, location);
    }

    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
        self.super_rvalue(rvalue, location);

        match rvalue {
            mir::Rvalue::AddressOf(mt, borrowed_place) => {
                if !borrowed_place.is_indirect()
                    && self.address_of_allows_mutation(*mt, *borrowed_place)
                {
                    let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
                    if Q::in_any_value_of_ty(self.ccx, place_ty) {
                        self.state.qualif.insert(borrowed_place.local);
                        self.state.borrow.insert(borrowed_place.local);
                    }
                }
            }

            mir::Rvalue::Ref(_, kind, borrowed_place) => {
                if !borrowed_place.is_indirect() && self.ref_allows_mutation(*kind, *borrowed_place)
                {
                    let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
                    if Q::in_any_value_of_ty(self.ccx, place_ty) {
                        self.state.qualif.insert(borrowed_place.local);
                        self.state.borrow.insert(borrowed_place.local);
                    }
                }
            }

            mir::Rvalue::Cast(..)
            | mir::Rvalue::ShallowInitBox(..)
            | mir::Rvalue::Use(..)
            | mir::Rvalue::ThreadLocalRef(..)
            | mir::Rvalue::Repeat(..)
            | mir::Rvalue::Len(..)
            | mir::Rvalue::BinaryOp(..)
            | mir::Rvalue::CheckedBinaryOp(..)
            | mir::Rvalue::NullaryOp(..)
            | mir::Rvalue::UnaryOp(..)
            | mir::Rvalue::Discriminant(..)
            | mir::Rvalue::Aggregate(..) => {}
        }
    }

    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
        match statement.kind {
            StatementKind::StorageDead(local) => {
                self.state.qualif.remove(local);
                self.state.borrow.remove(local);
            }
            _ => self.super_statement(statement, location),
        }
    }

    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
        // The effect of assignment to the return place in `TerminatorKind::Call` is not applied
        // here; that occurs in `apply_call_return_effect`.

        if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
            let qualif = qualifs::in_operand::<Q, _>(
                self.ccx,
                &mut |l| self.state.qualif.contains(l),
                value,
            );

            if !place.is_indirect() {
                self.assign_qualif_direct(place, qualif);
            }
        }

        // We ignore borrow on drop because custom drop impls are not allowed in consts.
        // FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.

        // We need to assign qualifs to the dropped location before visiting the operand that
        // replaces it since qualifs can be cleared on move.
        self.super_terminator(terminator, location);
    }
}

/// The dataflow analysis used to propagate qualifs on arbitrary CFGs.
pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> {
    ccx: &'a ConstCx<'mir, 'tcx>,
    _qualif: PhantomData<Q>,
}

impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    pub(super) fn new(_: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self {
        FlowSensitiveAnalysis { ccx, _qualif: PhantomData }
    }

    fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> {
        TransferFunction::<Q>::new(self.ccx, state)
    }
}

#[derive(Debug, PartialEq, Eq)]
pub(super) struct State {
    /// Describes whether a local contains qualif.
    pub qualif: BitSet<Local>,
    /// Describes whether a local's address escaped and it might become qualified as a result an
    /// indirect mutation.
    pub borrow: BitSet<Local>,
}

impl Clone for State {
    fn clone(&self) -> Self {
        State { qualif: self.qualif.clone(), borrow: self.borrow.clone() }
    }

    // Data flow engine when possible uses `clone_from` for domain values.
    // Providing an implementation will avoid some intermediate memory allocations.
    fn clone_from(&mut self, other: &Self) {
        self.qualif.clone_from(&other.qualif);
        self.borrow.clone_from(&other.borrow);
    }
}

impl State {
    #[inline]
    pub(super) fn contains(&self, local: Local) -> bool {
        self.qualif.contains(local)
    }
}

impl<C> DebugWithContext<C> for State {
    fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("qualif: ")?;
        self.qualif.fmt_with(ctxt, f)?;
        f.write_str(" borrow: ")?;
        self.borrow.fmt_with(ctxt, f)?;
        Ok(())
    }

    fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self == old {
            return Ok(());
        }

        if self.qualif != old.qualif {
            f.write_str("qualif: ")?;
            self.qualif.fmt_diff_with(&old.qualif, ctxt, f)?;
            f.write_str("\n")?;
        }

        if self.borrow != old.borrow {
            f.write_str("borrow: ")?;
            self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?;
            f.write_str("\n")?;
        }

        Ok(())
    }
}

impl JoinSemiLattice for State {
    fn join(&mut self, other: &Self) -> bool {
        self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow)
    }
}

impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    type Domain = State;

    const NAME: &'static str = Q::ANALYSIS_NAME;

    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
        State {
            qualif: BitSet::new_empty(body.local_decls.len()),
            borrow: BitSet::new_empty(body.local_decls.len()),
        }
    }

    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
        self.transfer_function(state).initialize_state();
    }
}

impl<Q> rustc_mir_dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    fn apply_statement_effect(
        &self,
        state: &mut Self::Domain,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        self.transfer_function(state).visit_statement(statement, location);
    }

    fn apply_terminator_effect(
        &self,
        state: &mut Self::Domain,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    ) {
        self.transfer_function(state).visit_terminator(terminator, location);
    }

    fn apply_call_return_effect(
        &self,
        state: &mut Self::Domain,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: mir::Place<'tcx>,
    ) {
        self.transfer_function(state).apply_call_return_effect(block, func, args, return_place)
    }
}
<|endoftext|>


<commit_before>//! A module providing IRC connections for use by `IrcServer`s.
use std::fs::File;
use std::fmt;
use std::io::Read;

use encoding::EncoderTrap;
use encoding::label::encoding_from_whatwg_label;
use futures::future;
use futures::{Async, Poll, Future, Sink, StartSend, Stream};
use native_tls::{Certificate, TlsConnector, Pkcs12};
use tokio::net::{ConnectFuture, TcpStream};
use tokio_io::AsyncRead;
use tokio_mockstream::MockStream;
use tokio_tls::{TlsConnectorExt, TlsStream};

use error;
use client::data::Config;
use client::transport::{IrcTransport, LogView, Logged};
use proto::{IrcCodec, Message};

/// An IRC connection used internally by `IrcServer`.
pub enum Connection {
    #[doc(hidden)]
    Unsecured(IrcTransport<TcpStream>),
    #[doc(hidden)]
    Secured(IrcTransport<TlsStream<TcpStream>>),
    #[doc(hidden)]
    Mock(Logged<MockStream>),
}

impl fmt::Debug for Connection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            match *self {
                Connection::Unsecured(_) => "Connection::Unsecured(...)",
                Connection::Secured(_) => "Connection::Secured(...)",
                Connection::Mock(_) => "Connection::Mock(...)",
            }
        )
    }
}

/// A future representing an eventual `Connection`.
pub enum ConnectionFuture {
    #[doc(hidden)]
    Unsecured(Config, ConnectFuture),
    #[doc(hidden)]
    Secured(Config, ConnectFuture, TlsConnector),
    #[doc(hidden)]
    Mock(Config),
}

impl fmt::Debug for ConnectionFuture {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}({:?}, ...)",
            match *self {
                ConnectionFuture::Unsecured(_, _) => "ConnectionFuture::Unsecured",
                ConnectionFuture::Secured(_, _, _) => "ConnectionFuture::Secured",
                ConnectionFuture::Mock(_) => "ConnectionFuture::Mock",
            },
            match *self {
                ConnectionFuture::Unsecured(ref cfg, _) |
                ConnectionFuture::Secured(ref cfg, _, _) |
                ConnectionFuture::Mock(ref cfg) => cfg,
            }
        )
    }
}

impl Future for ConnectionFuture {
    type Item = Connection;
    type Error = error::IrcError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match *self {
            ConnectionFuture::Unsecured(ref config, ref mut inner) => {
                let framed = try_ready!(inner.poll()).framed(IrcCodec::new(config.encoding())?);
                let transport = IrcTransport::new(config, framed);

                Ok(Async::Ready(Connection::Unsecured(transport)))
            }
            ConnectionFuture::Secured(ref config, ref mut inner, ref connector) => {
                let domain = format!("{}", config.server().expect("should already be tested"));
                let mut inner = inner.map_err(|e| {
                    let res: error::IrcError = e.into();
                    res
                }).and_then(move |socket| {
                    connector.connect_async(&domain, socket).map_err(
                        |e| e.into(),
                    )
                });
                let framed = try_ready!(inner.poll()).framed(IrcCodec::new(config.encoding())?);
                let transport = IrcTransport::new(config, framed);

                Ok(Async::Ready(Connection::Secured(transport)))
            }
            ConnectionFuture::Mock(ref config) => {
                let enc: error::Result<_> = encoding_from_whatwg_label(
                    config.encoding()
                ).ok_or_else(|| error::IrcError::UnknownCodec {
                    codec: config.encoding().to_owned(),
                });
                let encoding = enc?;
                let init_str = config.mock_initial_value();
                let initial: error::Result<_> = {
                    encoding.encode(init_str, EncoderTrap::Replace).map_err(|data| {
                        error::IrcError::CodecFailed {
                            codec: encoding.name(),
                            data: data.into_owned(),
                        }
                    })
                };

                let framed = MockStream::new(&initial?).framed(IrcCodec::new(config.encoding())?);
                let transport = IrcTransport::new(config, framed);

                Ok(Async::Ready(Connection::Mock(Logged::wrap(transport))))
            }
        }
    }
}

impl Connection {
    /// Creates a future yielding a new `Connection` using the specified `Config`.
    pub fn new(config: Config) -> impl Future<Item = Connection, Error = error::IrcError> {
        future::lazy(move || Connection::new_inner(config))
            .and_then(|connection_future| connection_future)
    }

    fn new_inner(config: Config) -> error::Result<ConnectionFuture> {
        if config.use_mock_connection() {
            Ok(ConnectionFuture::Mock(config))
        } else if config.use_ssl() {
            let domain = format!("{}", config.server()?);
            info!("Connecting via SSL to {}.", domain);
            let mut builder = TlsConnector::builder()?;
            if let Some(cert_path) = config.cert_path() {
                let mut file = File::open(cert_path)?;
                let mut cert_data = vec![];
                file.read_to_end(&mut cert_data)?;
                let cert = Certificate::from_der(&cert_data)?;
                builder.add_root_certificate(cert)?;
                info!("Added {} to trusted certificates.", cert_path);
            }
            if let Some(client_cert_path) = config.client_cert_path() {
                let client_cert_pass = config.client_cert_pass();
                let mut file = File::open(client_cert_path)?;
                let mut client_cert_data = vec![];
                file.read_to_end(&mut client_cert_data)?;
                let pkcs12_archive = Pkcs12::from_der(&client_cert_data, &client_cert_pass)?;
                builder.identity(pkcs12_archive)?;
                info!("Using {} for client certificate authentication.", client_cert_path);
            }
            let connector = builder.build()?;
            let socket_addr = config.socket_addr()?;
            Ok(ConnectionFuture::Secured(
                config,
                TcpStream::connect(&socket_addr),
                connector
            ))
        } else {
            info!("Connecting to {}.", config.server()?);
            let socket_addr = config.socket_addr()?;
            Ok(ConnectionFuture::Unsecured(
                config,
                TcpStream::connect(&socket_addr),
            ))
        }
    }

    /// Gets a view of the internal logging if and only if this connection is using a mock stream.
    /// Otherwise, this will always return `None`. This is used for unit testing.
    pub fn log_view(&self) -> Option<LogView> {
        match *self {
            Connection::Mock(ref inner) => Some(inner.view()),
            _ => None,
        }
    }
}

impl Stream for Connection {
    type Item = Message;
    type Error = error::IrcError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.poll(),
            Connection::Secured(ref mut inner) => inner.poll(),
            Connection::Mock(ref mut inner) => inner.poll(),
        }
    }
}

impl Sink for Connection {
    type SinkItem = Message;
    type SinkError = error::IrcError;

    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.start_send(item),
            Connection::Secured(ref mut inner) => inner.start_send(item),
            Connection::Mock(ref mut inner) => inner.start_send(item),
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.poll_complete(),
            Connection::Secured(ref mut inner) => inner.poll_complete(),
            Connection::Mock(ref mut inner) => inner.poll_complete(),
        }
    }
}
<commit_msg>Reverted some of the TLS changes from #141 because they broke TLS completely.<commit_after>//! A module providing IRC connections for use by `IrcServer`s.
use std::fs::File;
use std::fmt;
use std::io::Read;

use encoding::EncoderTrap;
use encoding::label::encoding_from_whatwg_label;
use futures::future;
use futures::{Async, Poll, Future, Sink, StartSend, Stream};
use native_tls::{Certificate, TlsConnector, Pkcs12};
use tokio::net::{ConnectFuture, TcpStream};
use tokio_io::AsyncRead;
use tokio_mockstream::MockStream;
use tokio_tls::{TlsConnectorExt, TlsStream};

use error;
use client::data::Config;
use client::transport::{IrcTransport, LogView, Logged};
use proto::{IrcCodec, Message};

/// An IRC connection used internally by `IrcServer`.
pub enum Connection {
    #[doc(hidden)]
    Unsecured(IrcTransport<TcpStream>),
    #[doc(hidden)]
    Secured(IrcTransport<TlsStream<TcpStream>>),
    #[doc(hidden)]
    Mock(Logged<MockStream>),
}

impl fmt::Debug for Connection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            match *self {
                Connection::Unsecured(_) => "Connection::Unsecured(...)",
                Connection::Secured(_) => "Connection::Secured(...)",
                Connection::Mock(_) => "Connection::Mock(...)",
            }
        )
    }
}

type TlsFuture = Box<Future<Error = error::IrcError, Item = TlsStream<TcpStream>> + Send>;

/// A future representing an eventual `Connection`.
pub enum ConnectionFuture {
    #[doc(hidden)]
    Unsecured(Config, ConnectFuture),
    #[doc(hidden)]
    Secured(Config, TlsFuture),
    #[doc(hidden)]
    Mock(Config),
}

impl fmt::Debug for ConnectionFuture {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}({:?}, ...)",
            match *self {
                ConnectionFuture::Unsecured(_, _) => "ConnectionFuture::Unsecured",
                ConnectionFuture::Secured(_, _) => "ConnectionFuture::Secured",
                ConnectionFuture::Mock(_) => "ConnectionFuture::Mock",
            },
            match *self {
                ConnectionFuture::Unsecured(ref cfg, _) |
                ConnectionFuture::Secured(ref cfg, _) |
                ConnectionFuture::Mock(ref cfg) => cfg,
            }
        )
    }
}

impl Future for ConnectionFuture {
    type Item = Connection;
    type Error = error::IrcError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match *self {
            ConnectionFuture::Unsecured(ref config, ref mut inner) => {
                let framed = try_ready!(inner.poll()).framed(IrcCodec::new(config.encoding())?);
                let transport = IrcTransport::new(config, framed);

                Ok(Async::Ready(Connection::Unsecured(transport)))
            }
            ConnectionFuture::Secured(ref config, ref mut inner) => {
                let framed = try_ready!(inner.poll()).framed(IrcCodec::new(config.encoding())?);
                let transport = IrcTransport::new(config, framed);

                Ok(Async::Ready(Connection::Secured(transport)))
            }
            ConnectionFuture::Mock(ref config) => {
                let enc: error::Result<_> = encoding_from_whatwg_label(
                    config.encoding()
                ).ok_or_else(|| error::IrcError::UnknownCodec {
                    codec: config.encoding().to_owned(),
                });
                let encoding = enc?;
                let init_str = config.mock_initial_value();
                let initial: error::Result<_> = {
                    encoding.encode(init_str, EncoderTrap::Replace).map_err(|data| {
                        error::IrcError::CodecFailed {
                            codec: encoding.name(),
                            data: data.into_owned(),
                        }
                    })
                };

                let framed = MockStream::new(&initial?).framed(IrcCodec::new(config.encoding())?);
                let transport = IrcTransport::new(config, framed);

                Ok(Async::Ready(Connection::Mock(Logged::wrap(transport))))
            }
        }
    }
}

impl Connection {
    /// Creates a future yielding a new `Connection` using the specified `Config`.
    pub fn new(config: Config) -> impl Future<Item = Connection, Error = error::IrcError> {
        future::lazy(move || Connection::new_inner(config))
            .and_then(|connection_future| connection_future)
    }

    fn new_inner(config: Config) -> error::Result<ConnectionFuture> {
        if config.use_mock_connection() {
            Ok(ConnectionFuture::Mock(config))
        } else if config.use_ssl() {
            let domain = format!("{}", config.server()?);
            info!("Connecting via SSL to {}.", domain);
            let mut builder = TlsConnector::builder()?;

            if let Some(cert_path) = config.cert_path() {
                let mut file = File::open(cert_path)?;
                let mut cert_data = vec![];
                file.read_to_end(&mut cert_data)?;
                let cert = Certificate::from_der(&cert_data)?;
                builder.add_root_certificate(cert)?;
                info!("Added {} to trusted certificates.", cert_path);
            }

            if let Some(client_cert_path) = config.client_cert_path() {
                let client_cert_pass = config.client_cert_pass();
                let mut file = File::open(client_cert_path)?;
                let mut client_cert_data = vec![];
                file.read_to_end(&mut client_cert_data)?;
                let pkcs12_archive = Pkcs12::from_der(&client_cert_data, &client_cert_pass)?;
                builder.identity(pkcs12_archive)?;
                info!("Using {} for client certificate authentication.", client_cert_path);
            }

            let connector = builder.build()?;
            let socket_addr = config.socket_addr()?;

            let stream = TcpStream::connect(&socket_addr).map_err(|e| {
                let res: error::IrcError = e.into();
                res
            }).and_then(move |socket| {
                connector.connect_async(&domain, socket).map_err(|e| e.into())
            });

            Ok(ConnectionFuture::Secured(config, Box::new(stream)))
        } else {
            info!("Connecting to {}.", config.server()?);
            let socket_addr = config.socket_addr()?;
            Ok(ConnectionFuture::Unsecured(
                config,
                TcpStream::connect(&socket_addr),
            ))
        }
    }

    /// Gets a view of the internal logging if and only if this connection is using a mock stream.
    /// Otherwise, this will always return `None`. This is used for unit testing.
    pub fn log_view(&self) -> Option<LogView> {
        match *self {
            Connection::Mock(ref inner) => Some(inner.view()),
            _ => None,
        }
    }
}

impl Stream for Connection {
    type Item = Message;
    type Error = error::IrcError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.poll(),
            Connection::Secured(ref mut inner) => inner.poll(),
            Connection::Mock(ref mut inner) => inner.poll(),
        }
    }
}

impl Sink for Connection {
    type SinkItem = Message;
    type SinkError = error::IrcError;

    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.start_send(item),
            Connection::Secured(ref mut inner) => inner.start_send(item),
            Connection::Mock(ref mut inner) => inner.start_send(item),
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.poll_complete(),
            Connection::Secured(ref mut inner) => inner.poll_complete(),
            Connection::Mock(ref mut inner) => inner.poll_complete(),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate rle_vec;

use test::Bencher;
use rle_vec::RleVec;

fn test_rle_vec() -> RleVec<u64> {
    let mut r = RleVec::new();
    for v in 1..1001 {
        for _ in 0..5 {
            r.push(v);
        }
    }
    r
}

fn test_vec() -> Vec<u64> {
    let mut r = Vec::new();
    for v in 1..1001 {
        for _ in 0 ..5 {
            r.push(v);
        }
    }
    r
}

#[bench]
fn create_1000_runs_length_5(b: &mut Bencher) {
    b.iter(|| {
        let r = test_rle_vec();
        assert_eq!(r.len(), 5000);
    });
}

#[bench]
fn create_vec_1000_runs_length_5(b: &mut Bencher) {
    b.iter(|| {
        let r = test_vec();
        assert_eq!(r.len(), 5000);
    });
}

#[bench]
fn index_100_from_test(b: &mut Bencher) {
    let r = test_rle_vec();
    b.iter(|| {
        for i in 800..900 {
            let _ = r[i];
        }
    });
}

#[bench]
fn index_100_from_vec(b: &mut Bencher) {
    let r = test_vec();
    b.iter(|| {
        for i in 800..900 {
            let _ = r[i];
        }
    });
}

#[bench]
fn set_100_with_split(b: &mut Bencher) {
    b.iter(|| {
        let mut r = test_rle_vec();
        let mut i = 2;
        let mut v = 0;
        for _ in 0..100 {
            r.set(i, v);
            i += 50;
            v += 10;
        }
        assert_eq!(r.len(), 5000);
        assert_eq!(r.runs_len(), 1200);
    });
}

#[bench]
fn set_100_without_split(b: &mut Bencher) {
    b.iter(|| {
        let mut r = test_rle_vec();
        let mut i = 2;
        let mut v = 1;
        for _ in 0..100 {
            r.set(i, v);
            i += 50;
            v += 10;
        }
        assert_eq!(r.len(), 5000);
        assert_eq!(r.runs_len(), 1000);
    });
}

#[bench]
fn set_100_vec(b: &mut Bencher) {
    b.iter(|| {
        let mut r = test_vec();
        let mut i = 2;
        let mut v = 1;
        for _ in 0..100 {
            r[i] = v;
            i += 50;
            v += 10;
        }
    });
}

#[bench]
fn insert_100_with_split(b: &mut Bencher) {
    b.iter(|| {
        let mut r = test_rle_vec();
        let mut i = 2;
        let v = 0;
        for _ in 0..100 {
            r.insert(i, v);
            i += 50 + 1;
        }
        assert_eq!(r.len(), 5100);
        assert_eq!(r.runs_len(), 1200);
    });
}

#[bench]
fn insert_100_without_split(b: &mut Bencher) {
    b.iter(|| {
        let mut r = test_rle_vec();
        let mut i = 2;
        let mut v = 1;
        for _ in 0..100 {
            r.insert(i, v);
            i += 50 + 1;
            v += 10;
        }
        assert_eq!(r.len(), 5100);
        assert_eq!(r.runs_len(), 1000);
    });
}

#[bench]
fn insert_100_vec(b: &mut Bencher) {
    b.iter(|| {
        let mut r = test_vec();
        let mut i = 2;
        let mut v = 0;
        for _ in 0..100 {
            r.insert(i, v);
            i += 50 + 1;
            v += 10;
        }
        assert_eq!(r.len(), 5100);
    });
}

<commit_msg>bench: Remove some tests<commit_after><|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/. */

//! Contains routines for retrieving default config directories.
//! For linux based platforms, it uses the XDG base directory spec but provides
//! similar abstractions for non-linux platforms.

#[cfg(target_os = "android")]
use android_injected_glue;
#[cfg(any(target_os = "macos", target_os = "windows"))]
use std::env;
#[cfg(target_os = "android")]
use std::ffi::CStr;
use std::path::PathBuf;
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
use xdg;

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn default_config_dir() -> PathBuf {
    let xdg_dirs = xdg::BaseDirectories::with_profile("servo", "default").unwrap();
    xdg_dirs.get_config_home()
}

#[cfg(target_os = "android")]
#[allow(unsafe_code)]
pub fn default_config_dir() -> PathBuf {
    let dir = unsafe {
        CStr::from_ptr((*android_injected_glue::get_app().activity).externalDataPath)
    };
    PathBuf::from(dir.to_str().unwrap())
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn default_data_dir() -> Option<PathBuf> {
    let xdg_dirs = xdg::BaseDirectories::with_profile("servo", "default").unwrap();
    let data_dir = xdg_dirs.get_data_home();
    Some(data_dir)
}

#[cfg(target_os = "android")]
#[allow(unsafe_code)]
pub fn default_data_dir() -> Option<PathBuf> {
    let dir = unsafe {
        CStr::from_ptr((*android_injected_glue::get_app().activity).internalDataPath)
    };
    Some(PathBuf::from(dir.to_str().unwrap()))
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn default_cache_dir() -> Option<PathBuf> {
    let xdg_dirs = xdg::BaseDirectories::with_profile("servo", "default").unwrap();
    let cache_dir = xdg_dirs.get_cache_home();
    Some(cache_dir)
}

#[cfg(target_os = "android")]
#[allow(unsafe_code)]
pub fn default_cache_dir() -> Option<PathBuf> {
    // TODO: Use JNI to call context.getCacheDir().
    // There is no equivalent function in NDK/NativeActivity.
    let dir = unsafe {
        CStr::from_ptr((*android_injected_glue::get_app().activity).externalDataPath)
    };
    Some(PathBuf::from(dir.to_str().unwrap()))
}

#[cfg(target_os = "macos")]
pub fn default_config_dir() -> PathBuf {
    let mut config_dir = env::home_dir().unwrap();
    config_dir.push("Library");
    config_dir.push("Application Support");
    config_dir.push("Servo");
    config_dir
}

#[cfg(target_os = "windows")]
pub fn default_config_dir() -> PathBuf {
    let mut config_dir = match env::var_os("APPDATA") {
        Some(appdata_path) => PathBuf::from(appdata_path),
        None => {
            let mut dir = env::home_dir().unwrap();
            dir.push("Appdata");
            dir.push("Roaming");
            dir
        }
    };
    config_dir.push("Servo");
    config_dir
}
<commit_msg>removed default_data_dir() and default_cache_dir() components/config/basedir.rs<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/. */

//! Contains routines for retrieving default config directories.
//! For linux based platforms, it uses the XDG base directory spec but provides
//! similar abstractions for non-linux platforms.

#[cfg(target_os = "android")]
use android_injected_glue;
#[cfg(any(target_os = "macos", target_os = "windows"))]
use std::env;
#[cfg(target_os = "android")]
use std::ffi::CStr;
use std::path::PathBuf;
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
use xdg;

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn default_config_dir() -> PathBuf {
    let xdg_dirs = xdg::BaseDirectories::with_profile("servo", "default").unwrap();
    xdg_dirs.get_config_home()
}

#[cfg(target_os = "android")]
#[allow(unsafe_code)]
pub fn default_config_dir() -> PathBuf {
    let dir = unsafe {
        CStr::from_ptr((*android_injected_glue::get_app().activity).externalDataPath)
    };
    PathBuf::from(dir.to_str().unwrap())
}

#[cfg(target_os = "macos")]
pub fn default_config_dir() -> PathBuf {
    let mut config_dir = env::home_dir().unwrap();
    config_dir.push("Library");
    config_dir.push("Application Support");
    config_dir.push("Servo");
    config_dir
}

#[cfg(target_os = "windows")]
pub fn default_config_dir() -> PathBuf {
    let mut config_dir = match env::var_os("APPDATA") {
        Some(appdata_path) => PathBuf::from(appdata_path),
        None => {
            let mut dir = env::home_dir().unwrap();
            dir.push("Appdata");
            dir.push("Roaming");
            dir
        }
    };
    config_dir.push("Servo");
    config_dir
}
<|endoftext|>