<commit_before>pub use crate::passes::BoxedResolver;
use crate::util;

use rustc_ast::token;
use rustc_ast::{self as ast, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::OnDrop;
use rustc_errors::registry::Registry;
use rustc_errors::{ErrorReported, Handler};
use rustc_lint::LintStore;
use rustc_middle::ty;
use rustc_parse::new_parser_from_source_str;
use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
use rustc_session::early_error;
use rustc_session::lint;
use rustc_session::parse::{CrateConfig, ParseSess};
use rustc_session::{DiagnosticOutput, Session};
use rustc_span::source_map::{FileLoader, FileName};
use std::path::PathBuf;
use std::result;
use std::sync::{Arc, Mutex};

pub type Result<T> = result::Result<T, ErrorReported>;

/// Represents a compiler session.
///
/// Can be used to run `rustc_interface` queries.
/// Created by passing [`Config`] to [`run_compiler`].
pub struct Compiler {
    pub(crate) sess: Lrc<Session>,
    codegen_backend: Lrc<Box<dyn CodegenBackend>>,
    pub(crate) input: Input,
    pub(crate) input_path: Option<PathBuf>,
    pub(crate) output_dir: Option<PathBuf>,
    pub(crate) output_file: Option<PathBuf>,
    pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
    pub(crate) override_queries:
        Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
}

impl Compiler {
    pub fn session(&self) -> &Lrc<Session> {
        &self.sess
    }
    pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
        &self.codegen_backend
    }
    pub fn input(&self) -> &Input {
        &self.input
    }
    pub fn output_dir(&self) -> &Option<PathBuf> {
        &self.output_dir
    }
    pub fn output_file(&self) -> &Option<PathBuf> {
        &self.output_file
    }
    pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
        &self.register_lints
    }
    pub fn build_output_filenames(
        &self,
        sess: &Session,
        attrs: &[ast::Attribute],
    ) -> OutputFilenames {
        util::build_output_filenames(
            &self.input,
            &self.output_dir,
            &self.output_file,
            &attrs,
            &sess,
        )
    }
}

/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
    rustc_span::with_default_session_globals(move || {
        let cfg = cfgspecs
            .into_iter()
            .map(|s| {
                let sess = ParseSess::with_silent_emitter();
                let filename = FileName::cfg_spec_source_code(&s);
                let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());

                macro_rules! error {
                    ($reason: expr) => {
                        early_error(
                            ErrorOutputType::default(),
                            &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s),
                        );
                    };
                }

                match &mut parser.parse_meta_item() {
                    Ok(meta_item) if parser.token == token::Eof => {
                        if meta_item.path.segments.len() != 1 {
                            error!("argument key must be an identifier");
                        }
                        match &meta_item.kind {
                            MetaItemKind::List(..) => {
                                error!(r#"expected `key` or `key="value"`"#);
                            }
                            MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
                                error!("argument value must be a string");
                            }
                            MetaItemKind::NameValue(..) | MetaItemKind::Word => {
                                let ident = meta_item.ident().expect("multi-segment cfg key");
                                return (ident.name, meta_item.value_str());
                            }
                        }
                    }
                    Ok(..) => {}
                    Err(err) => err.cancel(),
                }

                error!(r#"expected `key` or `key="value"`"#);
            })
            .collect::<CrateConfig>();
        cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect()
    })
}

/// The compiler configuration
pub struct Config {
    /// Command line options
    pub opts: config::Options,

    /// cfg! configuration in addition to the default ones
    pub crate_cfg: FxHashSet<(String, Option<String>)>,

    pub input: Input,
    pub input_path: Option<PathBuf>,
    pub output_dir: Option<PathBuf>,
    pub output_file: Option<PathBuf>,
    pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
    pub diagnostic_output: DiagnosticOutput,

    /// Set to capture stderr output during compiler execution
    pub stderr: Option<Arc<Mutex<Vec<u8>>>>,

    pub lint_caps: FxHashMap<lint::LintId, lint::Level>,

    /// This is a callback from the driver that is called when [`ParseSess`] is created.
    pub parse_sess_created: Option<Box<dyn FnOnce(&mut ParseSess) + Send>>,

    /// This is a callback from the driver that is called when we're registering lints;
    /// it is called during plugin registration when we have the LintStore in a non-shared state.
    ///
    /// Note that if you find a Some here you probably want to call that function in the new
    /// function being registered.
    pub register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,

    /// This is a callback from the driver that is called just after we have populated
    /// the list of queries.
    ///
    /// The second parameter is local providers and the third parameter is external providers.
    pub override_queries:
        Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,

    /// This is a callback from the driver that is called to create a codegen backend.
    pub make_codegen_backend:
        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,

    /// Registry of diagnostics codes.
    pub registry: Registry,
}

pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
    let registry = &config.registry;
    let (mut sess, codegen_backend) = util::create_session(
        config.opts,
        config.crate_cfg,
        config.diagnostic_output,
        config.file_loader,
        config.input_path.clone(),
        config.lint_caps,
        config.make_codegen_backend,
        registry.clone(),
    );

    if let Some(parse_sess_created) = config.parse_sess_created {
        parse_sess_created(&mut Lrc::get_mut(&mut sess).unwrap().parse_sess);
    }

    let compiler = Compiler {
        sess,
        codegen_backend,
        input: config.input,
        input_path: config.input_path,
        output_dir: config.output_dir,
        output_file: config.output_file,
        register_lints: config.register_lints,
        override_queries: config.override_queries,
    };

    rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
        let r = {
            let _sess_abort_error = OnDrop(|| {
                compiler.sess.finish_diagnostics(registry);
            });

            f(&compiler)
        };

        let prof = compiler.sess.prof.clone();
        prof.generic_activity("drop_compiler").run(move || drop(compiler));
        r
    })
}

pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
    tracing::trace!("run_compiler");
    let stderr = config.stderr.take();
    util::setup_callbacks_and_run_in_thread_pool_with_globals(
        config.opts.edition,
        config.opts.debugging_opts.threads,
        &stderr,
        || create_compiler_and_run(config, f),
    )
}

pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
    eprintln!("query stack during panic:");

    // Be careful relying on global state here: this code is called from
    // a panic hook, which means that the global `Handler` may be in a weird
    // state if it was responsible for triggering the panic.
    let i = ty::tls::with_context_opt(|icx| {
        if let Some(icx) = icx {
            icx.tcx.queries.try_print_query_stack(icx.tcx, icx.query, handler, num_frames)
        } else {
            0
        }
    });

    if num_frames == None || num_frames >= Some(i) {
        eprintln!("end of query stack");
    } else {
        eprintln!("we're just showing a limited slice of the query stack");
    }
}
<commit_msg>Change the `.unwrap` to `.expect` with a helpful message<commit_after>pub use crate::passes::BoxedResolver;
use crate::util;

use rustc_ast::token;
use rustc_ast::{self as ast, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::OnDrop;
use rustc_errors::registry::Registry;
use rustc_errors::{ErrorReported, Handler};
use rustc_lint::LintStore;
use rustc_middle::ty;
use rustc_parse::new_parser_from_source_str;
use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
use rustc_session::early_error;
use rustc_session::lint;
use rustc_session::parse::{CrateConfig, ParseSess};
use rustc_session::{DiagnosticOutput, Session};
use rustc_span::source_map::{FileLoader, FileName};
use std::path::PathBuf;
use std::result;
use std::sync::{Arc, Mutex};

pub type Result<T> = result::Result<T, ErrorReported>;

/// Represents a compiler session.
///
/// Can be used to run `rustc_interface` queries.
/// Created by passing [`Config`] to [`run_compiler`].
pub struct Compiler {
    pub(crate) sess: Lrc<Session>,
    codegen_backend: Lrc<Box<dyn CodegenBackend>>,
    pub(crate) input: Input,
    pub(crate) input_path: Option<PathBuf>,
    pub(crate) output_dir: Option<PathBuf>,
    pub(crate) output_file: Option<PathBuf>,
    pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
    pub(crate) override_queries:
        Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
}

impl Compiler {
    pub fn session(&self) -> &Lrc<Session> {
        &self.sess
    }
    pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
        &self.codegen_backend
    }
    pub fn input(&self) -> &Input {
        &self.input
    }
    pub fn output_dir(&self) -> &Option<PathBuf> {
        &self.output_dir
    }
    pub fn output_file(&self) -> &Option<PathBuf> {
        &self.output_file
    }
    pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
        &self.register_lints
    }
    pub fn build_output_filenames(
        &self,
        sess: &Session,
        attrs: &[ast::Attribute],
    ) -> OutputFilenames {
        util::build_output_filenames(
            &self.input,
            &self.output_dir,
            &self.output_file,
            &attrs,
            &sess,
        )
    }
}

/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
    rustc_span::with_default_session_globals(move || {
        let cfg = cfgspecs
            .into_iter()
            .map(|s| {
                let sess = ParseSess::with_silent_emitter();
                let filename = FileName::cfg_spec_source_code(&s);
                let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());

                macro_rules! error {
                    ($reason: expr) => {
                        early_error(
                            ErrorOutputType::default(),
                            &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s),
                        );
                    };
                }

                match &mut parser.parse_meta_item() {
                    Ok(meta_item) if parser.token == token::Eof => {
                        if meta_item.path.segments.len() != 1 {
                            error!("argument key must be an identifier");
                        }
                        match &meta_item.kind {
                            MetaItemKind::List(..) => {
                                error!(r#"expected `key` or `key="value"`"#);
                            }
                            MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
                                error!("argument value must be a string");
                            }
                            MetaItemKind::NameValue(..) | MetaItemKind::Word => {
                                let ident = meta_item.ident().expect("multi-segment cfg key");
                                return (ident.name, meta_item.value_str());
                            }
                        }
                    }
                    Ok(..) => {}
                    Err(err) => err.cancel(),
                }

                error!(r#"expected `key` or `key="value"`"#);
            })
            .collect::<CrateConfig>();
        cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect()
    })
}

/// The compiler configuration
pub struct Config {
    /// Command line options
    pub opts: config::Options,

    /// cfg! configuration in addition to the default ones
    pub crate_cfg: FxHashSet<(String, Option<String>)>,

    pub input: Input,
    pub input_path: Option<PathBuf>,
    pub output_dir: Option<PathBuf>,
    pub output_file: Option<PathBuf>,
    pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
    pub diagnostic_output: DiagnosticOutput,

    /// Set to capture stderr output during compiler execution
    pub stderr: Option<Arc<Mutex<Vec<u8>>>>,

    pub lint_caps: FxHashMap<lint::LintId, lint::Level>,

    /// This is a callback from the driver that is called when [`ParseSess`] is created.
    pub parse_sess_created: Option<Box<dyn FnOnce(&mut ParseSess) + Send>>,

    /// This is a callback from the driver that is called when we're registering lints;
    /// it is called during plugin registration when we have the LintStore in a non-shared state.
    ///
    /// Note that if you find a Some here you probably want to call that function in the new
    /// function being registered.
    pub register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,

    /// This is a callback from the driver that is called just after we have populated
    /// the list of queries.
    ///
    /// The second parameter is local providers and the third parameter is external providers.
    pub override_queries:
        Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,

    /// This is a callback from the driver that is called to create a codegen backend.
    pub make_codegen_backend:
        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,

    /// Registry of diagnostics codes.
    pub registry: Registry,
}

pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
    let registry = &config.registry;
    let (mut sess, codegen_backend) = util::create_session(
        config.opts,
        config.crate_cfg,
        config.diagnostic_output,
        config.file_loader,
        config.input_path.clone(),
        config.lint_caps,
        config.make_codegen_backend,
        registry.clone(),
    );

    if let Some(parse_sess_created) = config.parse_sess_created {
        parse_sess_created(
            &mut Lrc::get_mut(&mut sess)
                .expect("create_session() should never share the returned session")
                .parse_sess,
        );
    }

    let compiler = Compiler {
        sess,
        codegen_backend,
        input: config.input,
        input_path: config.input_path,
        output_dir: config.output_dir,
        output_file: config.output_file,
        register_lints: config.register_lints,
        override_queries: config.override_queries,
    };

    rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
        let r = {
            let _sess_abort_error = OnDrop(|| {
                compiler.sess.finish_diagnostics(registry);
            });

            f(&compiler)
        };

        let prof = compiler.sess.prof.clone();
        prof.generic_activity("drop_compiler").run(move || drop(compiler));
        r
    })
}

pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
    tracing::trace!("run_compiler");
    let stderr = config.stderr.take();
    util::setup_callbacks_and_run_in_thread_pool_with_globals(
        config.opts.edition,
        config.opts.debugging_opts.threads,
        &stderr,
        || create_compiler_and_run(config, f),
    )
}

pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
    eprintln!("query stack during panic:");

    // Be careful relying on global state here: this code is called from
    // a panic hook, which means that the global `Handler` may be in a weird
    // state if it was responsible for triggering the panic.
    let i = ty::tls::with_context_opt(|icx| {
        if let Some(icx) = icx {
            icx.tcx.queries.try_print_query_stack(icx.tcx, icx.query, handler, num_frames)
        } else {
            0
        }
    });

    if num_frames == None || num_frames >= Some(i) {
        eprintln!("end of query stack");
    } else {
        eprintln!("we're just showing a limited slice of the query stack");
    }
}
<|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/. */

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "bindgen")]
extern crate bindgen;
#[cfg(feature = "bindgen")]
extern crate log;
#[cfg(feature = "bindgen")]
extern crate regex;
#[cfg(feature = "bindgen")]
extern crate toml;
extern crate walkdir;

use std::env;
use std::path::Path;
use std::process::{Command, exit};
use walkdir::WalkDir;

#[cfg(feature = "gecko")]
mod build_gecko;

#[cfg(not(feature = "gecko"))]
mod build_gecko {
    pub fn generate() {}
}

#[cfg(windows)]
fn find_python() -> String {
    if Command::new("python2.7.exe").arg("--version").output().is_ok() {
        return "python2.7.exe".to_owned();
    }

    if Command::new("python27.exe").arg("--version").output().is_ok() {
        return "python27.exe".to_owned();
    }

    if Command::new("python.exe").arg("--version").output().is_ok() {
        return "python.exe".to_owned();
    }

    panic!(concat!("Can't find python (tried python2.7.exe, python27.exe, and python.exe)! ",
                   "Try fixing PATH or setting the PYTHON env var"));
}

#[cfg(not(windows))]
fn find_python() -> String {
    if Command::new("python2.7").arg("--version").output().unwrap().status.success() {
        "python2.7"
    } else {
        "python"
    }.to_owned()
}

lazy_static! {
    pub static ref PYTHON: String = env::var("PYTHON").ok().unwrap_or_else(find_python);
}

fn generate_properties() {
    for entry in WalkDir::new("properties") {
        let entry = entry.unwrap();
        match entry.path().extension().and_then(|e| e.to_str()) {
            Some("mako") | Some("rs") | Some("py") | Some("zip") => {
                println!("cargo:rerun-if-changed={}", entry.path().display());
            }
            _ => {}
        }
    }

    let script = Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
        .join("properties").join("build.py");
    let product = if cfg!(feature = "gecko") { "gecko" } else { "servo" };
    let status = Command::new(&*PYTHON)
        .arg(&script)
        .arg(product)
        .arg("style-crate")
        .envs(if std::mem::size_of::<Option<bool>>() == 1 {
            // FIXME: remove this envs() call
            // and make unconditional code that depends on RUSTC_HAS_PR45225
            // once Firefox requires Rust 1.23+

            // https://github.com/rust-lang/rust/pull/45225
            vec![("RUSTC_HAS_PR45225", "1")]
        } else {
            vec![]
        })
        .status()
        .unwrap();
    if !status.success() {
        exit(1)
    }
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:out_dir={}", env::var("OUT_DIR").unwrap());
    generate_properties();
    build_gecko::generate();
}
<commit_msg>Auto merge of #19540 - servo:style-features, r=emilio<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/. */

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "bindgen")]
extern crate bindgen;
#[cfg(feature = "bindgen")]
extern crate log;
#[cfg(feature = "bindgen")]
extern crate regex;
#[cfg(feature = "bindgen")]
extern crate toml;
extern crate walkdir;

use std::env;
use std::path::Path;
use std::process::{Command, exit};
use walkdir::WalkDir;

#[cfg(feature = "gecko")]
mod build_gecko;

#[cfg(not(feature = "gecko"))]
mod build_gecko {
    pub fn generate() {}
}

#[cfg(windows)]
fn find_python() -> String {
    if Command::new("python2.7.exe").arg("--version").output().is_ok() {
        return "python2.7.exe".to_owned();
    }

    if Command::new("python27.exe").arg("--version").output().is_ok() {
        return "python27.exe".to_owned();
    }

    if Command::new("python.exe").arg("--version").output().is_ok() {
        return "python.exe".to_owned();
    }

    panic!(concat!("Can't find python (tried python2.7.exe, python27.exe, and python.exe)! ",
                   "Try fixing PATH or setting the PYTHON env var"));
}

#[cfg(not(windows))]
fn find_python() -> String {
    if Command::new("python2.7").arg("--version").output().unwrap().status.success() {
        "python2.7"
    } else {
        "python"
    }.to_owned()
}

lazy_static! {
    pub static ref PYTHON: String = env::var("PYTHON").ok().unwrap_or_else(find_python);
}

fn generate_properties() {
    for entry in WalkDir::new("properties") {
        let entry = entry.unwrap();
        match entry.path().extension().and_then(|e| e.to_str()) {
            Some("mako") | Some("rs") | Some("py") | Some("zip") => {
                println!("cargo:rerun-if-changed={}", entry.path().display());
            }
            _ => {}
        }
    }

    let script = Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
        .join("properties").join("build.py");
    let product = if cfg!(feature = "gecko") { "gecko" } else { "servo" };
    let status = Command::new(&*PYTHON)
        .arg(&script)
        .arg(product)
        .arg("style-crate")
        .envs(if std::mem::size_of::<Option<bool>>() == 1 {
            // FIXME: remove this envs() call
            // and make unconditional code that depends on RUSTC_HAS_PR45225
            // once Firefox requires Rust 1.23+

            // https://github.com/rust-lang/rust/pull/45225
            vec![("RUSTC_HAS_PR45225", "1")]
        } else {
            vec![]
        })
        .status()
        .unwrap();
    if !status.success() {
        exit(1)
    }
}

fn main() {
    let gecko = cfg!(feature = "gecko");
    let servo = cfg!(feature = "servo");
    if !(gecko || servo) {
        panic!("The style crate requires enabling one of its 'servo' or 'gecko' feature flags");
    }
    if gecko && servo {
        panic!("The style crate does not support enabling both its 'servo' or 'gecko' \
                feature flags at the same time.");
    }
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:out_dir={}", env::var("OUT_DIR").unwrap());
    generate_properties();
    build_gecko::generate();
}
<|endoftext|>


<commit_before>//! Cranelift compilation context and main entry point.
//!
//! When compiling many small functions, it is important to avoid repeatedly allocating and
//! deallocating the data structures needed for compilation. The `Context` struct is used to hold
//! on to memory allocations between function compilations.
//!
//! The context does not hold a `TargetIsa` instance which has to be provided as an argument
//! instead. This is because an ISA instance is immutable and can be used by multiple compilation
//! contexts concurrently. Typically, you would have one context per compilation thread and only a
//! single ISA instance.

use crate::binemit::{
    relax_branches, shrink_instructions, CodeInfo, MemoryCodeSink, RelocSink, StackmapSink,
    TrapSink,
};
use crate::dce::do_dce;
use crate::dominator_tree::DominatorTree;
use crate::flowgraph::ControlFlowGraph;
use crate::ir::Function;
use crate::isa::TargetIsa;
use crate::legalize_function;
use crate::licm::do_licm;
use crate::loop_analysis::LoopAnalysis;
use crate::nan_canonicalization::do_nan_canonicalization;
use crate::postopt::do_postopt;
use crate::redundant_reload_remover::RedundantReloadRemover;
use crate::regalloc;
use crate::result::CodegenResult;
use crate::settings::{FlagsOrIsa, OptLevel};
use crate::simple_gvn::do_simple_gvn;
use crate::simple_preopt::do_preopt;
use crate::timing;
use crate::unreachable_code::eliminate_unreachable_code;
use crate::value_label::{build_value_labels_ranges, ComparableSourceLoc, ValueLabelsRanges};
use crate::verifier::{verify_context, verify_locations, VerifierErrors, VerifierResult};
use std::vec::Vec;

/// Persistent data structures and compilation pipeline.
pub struct Context {
    /// The function we're compiling.
    pub func: Function,

    /// The control flow graph of `func`.
    pub cfg: ControlFlowGraph,

    /// Dominator tree for `func`.
    pub domtree: DominatorTree,

    /// Register allocation context.
    pub regalloc: regalloc::Context,

    /// Loop analysis of `func`.
    pub loop_analysis: LoopAnalysis,

    /// Redundant-reload remover context.
    pub redundant_reload_remover: RedundantReloadRemover,
}

impl Context {
    /// Allocate a new compilation context.
    ///
    /// The returned instance should be reused for compiling multiple functions in order to avoid
    /// needless allocator thrashing.
    pub fn new() -> Self {
        Self::for_function(Function::new())
    }

    /// Allocate a new compilation context with an existing Function.
    ///
    /// The returned instance should be reused for compiling multiple functions in order to avoid
    /// needless allocator thrashing.
    pub fn for_function(func: Function) -> Self {
        Self {
            func,
            cfg: ControlFlowGraph::new(),
            domtree: DominatorTree::new(),
            regalloc: regalloc::Context::new(),
            loop_analysis: LoopAnalysis::new(),
            redundant_reload_remover: RedundantReloadRemover::new(),
        }
    }

    /// Clear all data structures in this context.
    pub fn clear(&mut self) {
        self.func.clear();
        self.cfg.clear();
        self.domtree.clear();
        self.regalloc.clear();
        self.loop_analysis.clear();
        self.redundant_reload_remover.clear();
    }

    /// Compile the function, and emit machine code into a `Vec<u8>`.
    ///
    /// Run the function through all the passes necessary to generate code for the target ISA
    /// represented by `isa`, as well as the final step of emitting machine code into a
    /// `Vec<u8>`. The machine code is not relocated. Instead, any relocations are emitted
    /// into `relocs`.
    ///
    /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as
    /// needed, so it provides a safe interface.
    ///
    /// Returns information about the function's code and read-only data.
    pub fn compile_and_emit(
        &mut self,
        isa: &dyn TargetIsa,
        mem: &mut Vec<u8>,
        relocs: &mut dyn RelocSink,
        traps: &mut dyn TrapSink,
        stackmaps: &mut dyn StackmapSink,
    ) -> CodegenResult<CodeInfo> {
        let info = self.compile(isa)?;
        let old_len = mem.len();
        mem.resize(old_len + info.total_size as usize, 0);
        let new_info = unsafe {
            self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps, stackmaps)
        };
        debug_assert!(new_info == info);
        Ok(info)
    }

    /// Compile the function.
    ///
    /// Run the function through all the passes necessary to generate code for the target ISA
    /// represented by `isa`. This does not include the final step of emitting machine code into a
    /// code sink.
    ///
    /// Returns information about the function's code and read-only data.
    pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> {
        let _tt = timing::compile();
        self.verify_if(isa)?;

        self.compute_cfg();
        if isa.flags().opt_level() != OptLevel::Fastest {
            self.preopt(isa)?;
        }
        if isa.flags().enable_nan_canonicalization() {
            self.canonicalize_nans(isa)?;
        }
        self.legalize(isa)?;
        if isa.flags().opt_level() != OptLevel::Fastest {
            self.postopt(isa)?;
        }
        if isa.flags().opt_level() == OptLevel::Best {
            self.compute_domtree();
            self.compute_loop_analysis();
            self.licm(isa)?;
            self.simple_gvn(isa)?;
        }
        self.compute_domtree();
        self.eliminate_unreachable_code(isa)?;
        if isa.flags().opt_level() != OptLevel::Fastest {
            self.dce(isa)?;
        }
        self.regalloc(isa)?;
        self.prologue_epilogue(isa)?;
        if isa.flags().opt_level() == OptLevel::Best {
            self.redundant_reload_remover(isa)?;
            self.shrink_instructions(isa)?;
        }
        self.relax_branches(isa)
    }

    /// Emit machine code directly into raw memory.
    ///
    /// Write all of the function's machine code to the memory at `mem`. The size of the machine
    /// code is returned by `compile` above.
    ///
    /// The machine code is not relocated. Instead, any relocations are emitted into `relocs`.
    ///
    /// This function is unsafe since it does not perform bounds checking on the memory buffer,
    /// and it can't guarantee that the `mem` pointer is valid.
    ///
    /// Returns information about the emitted code and data.
    pub unsafe fn emit_to_memory(
        &self,
        isa: &dyn TargetIsa,
        mem: *mut u8,
        relocs: &mut dyn RelocSink,
        traps: &mut dyn TrapSink,
        stackmaps: &mut dyn StackmapSink,
    ) -> CodeInfo {
        let _tt = timing::binemit();
        let mut sink = MemoryCodeSink::new(mem, relocs, traps, stackmaps);
        isa.emit_function_to_memory(&self.func, &mut sink);
        sink.info
    }

    /// Run the verifier on the function.
    ///
    /// Also check that the dominator tree and control flow graph are consistent with the function.
    pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
        let mut errors = VerifierErrors::default();
        let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }

    /// Run the verifier only if the `enable_verifier` setting is true.
    pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> {
        let fisa = fisa.into();
        if fisa.flags.enable_verifier() {
            self.verify(fisa)?;
        }
        Ok(())
    }

    /// Run the locations verifier on the function.
    pub fn verify_locations(&self, isa: &dyn TargetIsa) -> VerifierResult<()> {
        let mut errors = VerifierErrors::default();
        let _ = verify_locations(isa, &self.func, &self.cfg, None, &mut errors);

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }

    /// Run the locations verifier only if the `enable_verifier` setting is true.
    pub fn verify_locations_if(&self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        if isa.flags().enable_verifier() {
            self.verify_locations(isa)?;
        }
        Ok(())
    }

    /// Perform dead-code elimination on the function.
    pub fn dce<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> {
        do_dce(&mut self.func, &mut self.domtree);
        self.verify_if(fisa)?;
        Ok(())
    }

    /// Perform pre-legalization rewrites on the function.
    pub fn preopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        do_preopt(&mut self.func, &mut self.cfg);
        self.verify_if(isa)?;
        Ok(())
    }

    /// Perform NaN canonicalizing rewrites on the function.
    pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        do_nan_canonicalization(&mut self.func);
        self.verify_if(isa)
    }

    /// Run the legalizer for `isa` on the function.
    pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        // Legalization invalidates the domtree and loop_analysis by mutating the CFG.
        // TODO: Avoid doing this when legalization doesn't actually mutate the CFG.
        self.domtree.clear();
        self.loop_analysis.clear();
        legalize_function(&mut self.func, &mut self.cfg, isa);
        self.verify_if(isa)
    }

    /// Perform post-legalization rewrites on the function.
    pub fn postopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        do_postopt(&mut self.func, isa);
        self.verify_if(isa)?;
        Ok(())
    }

    /// Compute the control flow graph.
    pub fn compute_cfg(&mut self) {
        self.cfg.compute(&self.func)
    }

    /// Compute dominator tree.
    pub fn compute_domtree(&mut self) {
        self.domtree.compute(&self.func, &self.cfg)
    }

    /// Compute the loop analysis.
    pub fn compute_loop_analysis(&mut self) {
        self.loop_analysis
            .compute(&self.func, &self.cfg, &self.domtree)
    }

    /// Compute the control flow graph and dominator tree.
    pub fn flowgraph(&mut self) {
        self.compute_cfg();
        self.compute_domtree()
    }

    /// Perform simple GVN on the function.
    pub fn simple_gvn<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> {
        do_simple_gvn(&mut self.func, &mut self.domtree);
        self.verify_if(fisa)
    }

    /// Perform LICM on the function.
    pub fn licm(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        do_licm(
            isa,
            &mut self.func,
            &mut self.cfg,
            &mut self.domtree,
            &mut self.loop_analysis,
        );
        self.verify_if(isa)
    }

    /// Perform unreachable code elimination.
    pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
    where
        FOI: Into<FlagsOrIsa<'a>>,
    {
        eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
        self.verify_if(fisa)
    }

    /// Run the register allocator.
    pub fn regalloc(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        self.regalloc
            .run(isa, &mut self.func, &mut self.cfg, &mut self.domtree)
    }

    /// Insert prologue and epilogues after computing the stack frame layout.
    pub fn prologue_epilogue(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        isa.prologue_epilogue(&mut self.func)?;
        self.verify_if(isa)?;
        self.verify_locations_if(isa)?;
        Ok(())
    }

    /// Do redundant-reload removal after allocation of both registers and stack slots.
    pub fn redundant_reload_remover(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        self.redundant_reload_remover
            .run(isa, &mut self.func, &self.cfg);
        self.verify_if(isa)?;
        Ok(())
    }

    /// Run the instruction shrinking pass.
    pub fn shrink_instructions(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        shrink_instructions(&mut self.func, isa);
        self.verify_if(isa)?;
        self.verify_locations_if(isa)?;
        Ok(())
    }

    /// Run the branch relaxation pass and return information about the function's code and
    /// read-only data.
    pub fn relax_branches(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> {
        let info = relax_branches(&mut self.func, &mut self.cfg, &mut self.domtree, isa)?;
        self.verify_if(isa)?;
        self.verify_locations_if(isa)?;
        Ok(info)
    }

    /// Builds ranges and location for specified value labels.
    pub fn build_value_labels_ranges(
        &self,
        isa: &dyn TargetIsa,
    ) -> CodegenResult<ValueLabelsRanges> {
        Ok(build_value_labels_ranges::<ComparableSourceLoc>(
            &self.func,
            &self.regalloc,
            isa,
        ))
    }
}
<commit_msg>Log compiled and legalized functions<commit_after>//! Cranelift compilation context and main entry point.
//!
//! When compiling many small functions, it is important to avoid repeatedly allocating and
//! deallocating the data structures needed for compilation. The `Context` struct is used to hold
//! on to memory allocations between function compilations.
//!
//! The context does not hold a `TargetIsa` instance which has to be provided as an argument
//! instead. This is because an ISA instance is immutable and can be used by multiple compilation
//! contexts concurrently. Typically, you would have one context per compilation thread and only a
//! single ISA instance.

use crate::binemit::{
    relax_branches, shrink_instructions, CodeInfo, MemoryCodeSink, RelocSink, StackmapSink,
    TrapSink,
};
use crate::dce::do_dce;
use crate::dominator_tree::DominatorTree;
use crate::flowgraph::ControlFlowGraph;
use crate::ir::Function;
use crate::isa::TargetIsa;
use crate::legalize_function;
use crate::licm::do_licm;
use crate::loop_analysis::LoopAnalysis;
use crate::nan_canonicalization::do_nan_canonicalization;
use crate::postopt::do_postopt;
use crate::redundant_reload_remover::RedundantReloadRemover;
use crate::regalloc;
use crate::result::CodegenResult;
use crate::settings::{FlagsOrIsa, OptLevel};
use crate::simple_gvn::do_simple_gvn;
use crate::simple_preopt::do_preopt;
use crate::timing;
use crate::unreachable_code::eliminate_unreachable_code;
use crate::value_label::{build_value_labels_ranges, ComparableSourceLoc, ValueLabelsRanges};
use crate::verifier::{verify_context, verify_locations, VerifierErrors, VerifierResult};
use log::debug;
use std::vec::Vec;

/// Persistent data structures and compilation pipeline.
pub struct Context {
    /// The function we're compiling.
    pub func: Function,

    /// The control flow graph of `func`.
    pub cfg: ControlFlowGraph,

    /// Dominator tree for `func`.
    pub domtree: DominatorTree,

    /// Register allocation context.
    pub regalloc: regalloc::Context,

    /// Loop analysis of `func`.
    pub loop_analysis: LoopAnalysis,

    /// Redundant-reload remover context.
    pub redundant_reload_remover: RedundantReloadRemover,
}

impl Context {
    /// Allocate a new compilation context.
    ///
    /// The returned instance should be reused for compiling multiple functions in order to avoid
    /// needless allocator thrashing.
    pub fn new() -> Self {
        Self::for_function(Function::new())
    }

    /// Allocate a new compilation context with an existing Function.
    ///
    /// The returned instance should be reused for compiling multiple functions in order to avoid
    /// needless allocator thrashing.
    pub fn for_function(func: Function) -> Self {
        Self {
            func,
            cfg: ControlFlowGraph::new(),
            domtree: DominatorTree::new(),
            regalloc: regalloc::Context::new(),
            loop_analysis: LoopAnalysis::new(),
            redundant_reload_remover: RedundantReloadRemover::new(),
        }
    }

    /// Clear all data structures in this context.
    pub fn clear(&mut self) {
        self.func.clear();
        self.cfg.clear();
        self.domtree.clear();
        self.regalloc.clear();
        self.loop_analysis.clear();
        self.redundant_reload_remover.clear();
    }

    /// Compile the function, and emit machine code into a `Vec<u8>`.
    ///
    /// Run the function through all the passes necessary to generate code for the target ISA
    /// represented by `isa`, as well as the final step of emitting machine code into a
    /// `Vec<u8>`. The machine code is not relocated. Instead, any relocations are emitted
    /// into `relocs`.
    ///
    /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as
    /// needed, so it provides a safe interface.
    ///
    /// Returns information about the function's code and read-only data.
    pub fn compile_and_emit(
        &mut self,
        isa: &dyn TargetIsa,
        mem: &mut Vec<u8>,
        relocs: &mut dyn RelocSink,
        traps: &mut dyn TrapSink,
        stackmaps: &mut dyn StackmapSink,
    ) -> CodegenResult<CodeInfo> {
        let info = self.compile(isa)?;
        let old_len = mem.len();
        mem.resize(old_len + info.total_size as usize, 0);
        let new_info = unsafe {
            self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps, stackmaps)
        };
        debug_assert!(new_info == info);
        Ok(info)
    }

    /// Compile the function.
    ///
    /// Run the function through all the passes necessary to generate code for the target ISA
    /// represented by `isa`. This does not include the final step of emitting machine code into a
    /// code sink.
    ///
    /// Returns information about the function's code and read-only data.
    pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> {
        let _tt = timing::compile();
        self.verify_if(isa)?;
        debug!("Compiling:\n{}", self.func.display(isa));

        self.compute_cfg();
        if isa.flags().opt_level() != OptLevel::Fastest {
            self.preopt(isa)?;
        }
        if isa.flags().enable_nan_canonicalization() {
            self.canonicalize_nans(isa)?;
        }
        self.legalize(isa)?;
        if isa.flags().opt_level() != OptLevel::Fastest {
            self.postopt(isa)?;
        }
        if isa.flags().opt_level() == OptLevel::Best {
            self.compute_domtree();
            self.compute_loop_analysis();
            self.licm(isa)?;
            self.simple_gvn(isa)?;
        }
        self.compute_domtree();
        self.eliminate_unreachable_code(isa)?;
        if isa.flags().opt_level() != OptLevel::Fastest {
            self.dce(isa)?;
        }
        self.regalloc(isa)?;
        self.prologue_epilogue(isa)?;
        if isa.flags().opt_level() == OptLevel::Best {
            self.redundant_reload_remover(isa)?;
            self.shrink_instructions(isa)?;
        }
        let result = self.relax_branches(isa);

        debug!("Compiled:\n{}", self.func.display(isa));
        result
    }

    /// Emit machine code directly into raw memory.
    ///
    /// Write all of the function's machine code to the memory at `mem`. The size of the machine
    /// code is returned by `compile` above.
    ///
    /// The machine code is not relocated. Instead, any relocations are emitted into `relocs`.
    ///
    /// This function is unsafe since it does not perform bounds checking on the memory buffer,
    /// and it can't guarantee that the `mem` pointer is valid.
    ///
    /// Returns information about the emitted code and data.
    pub unsafe fn emit_to_memory(
        &self,
        isa: &dyn TargetIsa,
        mem: *mut u8,
        relocs: &mut dyn RelocSink,
        traps: &mut dyn TrapSink,
        stackmaps: &mut dyn StackmapSink,
    ) -> CodeInfo {
        let _tt = timing::binemit();
        let mut sink = MemoryCodeSink::new(mem, relocs, traps, stackmaps);
        isa.emit_function_to_memory(&self.func, &mut sink);
        sink.info
    }

    /// Run the verifier on the function.
    ///
    /// Also check that the dominator tree and control flow graph are consistent with the function.
    pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
        let mut errors = VerifierErrors::default();
        let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }

    /// Run the verifier only if the `enable_verifier` setting is true.
    pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> {
        let fisa = fisa.into();
        if fisa.flags.enable_verifier() {
            self.verify(fisa)?;
        }
        Ok(())
    }

    /// Run the locations verifier on the function.
    pub fn verify_locations(&self, isa: &dyn TargetIsa) -> VerifierResult<()> {
        let mut errors = VerifierErrors::default();
        let _ = verify_locations(isa, &self.func, &self.cfg, None, &mut errors);

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }

    /// Run the locations verifier only if the `enable_verifier` setting is true.
    pub fn verify_locations_if(&self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        if isa.flags().enable_verifier() {
            self.verify_locations(isa)?;
        }
        Ok(())
    }

    /// Perform dead-code elimination on the function.
    pub fn dce<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> {
        do_dce(&mut self.func, &mut self.domtree);
        self.verify_if(fisa)?;
        Ok(())
    }

    /// Perform pre-legalization rewrites on the function.
    pub fn preopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        do_preopt(&mut self.func, &mut self.cfg);
        self.verify_if(isa)?;
        Ok(())
    }

    /// Perform NaN canonicalizing rewrites on the function.
    pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        do_nan_canonicalization(&mut self.func);
        self.verify_if(isa)
    }

    /// Run the legalizer for `isa` on the function.
    pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        // Legalization invalidates the domtree and loop_analysis by mutating the CFG.
        // TODO: Avoid doing this when legalization doesn't actually mutate the CFG.
        self.domtree.clear();
        self.loop_analysis.clear();
        legalize_function(&mut self.func, &mut self.cfg, isa);
        debug!("Legalized:\n{}", self.func.display(isa));
        self.verify_if(isa)
    }

    /// Perform post-legalization rewrites on the function.
    pub fn postopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        do_postopt(&mut self.func, isa);
        self.verify_if(isa)?;
        Ok(())
    }

    /// Compute the control flow graph.
    pub fn compute_cfg(&mut self) {
        self.cfg.compute(&self.func)
    }

    /// Compute dominator tree.
    pub fn compute_domtree(&mut self) {
        self.domtree.compute(&self.func, &self.cfg)
    }

    /// Compute the loop analysis.
    pub fn compute_loop_analysis(&mut self) {
        self.loop_analysis
            .compute(&self.func, &self.cfg, &self.domtree)
    }

    /// Compute the control flow graph and dominator tree.
    pub fn flowgraph(&mut self) {
        self.compute_cfg();
        self.compute_domtree()
    }

    /// Perform simple GVN on the function.
    pub fn simple_gvn<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> {
        do_simple_gvn(&mut self.func, &mut self.domtree);
        self.verify_if(fisa)
    }

    /// Perform LICM on the function.
    pub fn licm(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        do_licm(
            isa,
            &mut self.func,
            &mut self.cfg,
            &mut self.domtree,
            &mut self.loop_analysis,
        );
        self.verify_if(isa)
    }

    /// Perform unreachable code elimination.
    pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
    where
        FOI: Into<FlagsOrIsa<'a>>,
    {
        eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
        self.verify_if(fisa)
    }

    /// Run the register allocator.
    pub fn regalloc(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        self.regalloc
            .run(isa, &mut self.func, &mut self.cfg, &mut self.domtree)
    }

    /// Insert prologue and epilogues after computing the stack frame layout.
    pub fn prologue_epilogue(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        isa.prologue_epilogue(&mut self.func)?;
        self.verify_if(isa)?;
        self.verify_locations_if(isa)?;
        Ok(())
    }

    /// Do redundant-reload removal after allocation of both registers and stack slots.
    pub fn redundant_reload_remover(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        self.redundant_reload_remover
            .run(isa, &mut self.func, &self.cfg);
        self.verify_if(isa)?;
        Ok(())
    }

    /// Run the instruction shrinking pass.
    pub fn shrink_instructions(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
        shrink_instructions(&mut self.func, isa);
        self.verify_if(isa)?;
        self.verify_locations_if(isa)?;
        Ok(())
    }

    /// Run the branch relaxation pass and return information about the function's code and
    /// read-only data.
    pub fn relax_branches(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> {
        let info = relax_branches(&mut self.func, &mut self.cfg, &mut self.domtree, isa)?;
        self.verify_if(isa)?;
        self.verify_locations_if(isa)?;
        Ok(info)
    }

    /// Builds ranges and location for specified value labels.
    pub fn build_value_labels_ranges(
        &self,
        isa: &dyn TargetIsa,
    ) -> CodegenResult<ValueLabelsRanges> {
        Ok(build_value_labels_ranges::<ComparableSourceLoc>(
            &self.func,
            &self.regalloc,
            isa,
        ))
    }
}
<|endoftext|>


<commit_before>//!
//! # Brief summary of Vulkan
//!
//! - The `Instance` object is the API entry point. It is the first object you must create before
//!   starting to use Vulkan.
//!
//! - The `PhysicalDevice` object represents an implementation of Vulkan available on the system
//!   (eg. a graphics card, a CPU implementation, multiple graphics card working together, etc.).
//!   Physical devices can be enumerated from an instance with `PhysicalDevice::enumerate()`.
//!
//! - Once you have chosen a physical device to use, you must a `Device` object from it. The
//!   `Device` is another very important object, as it represents an open channel of
//!   communicaton with the physical device.
//!
//! - `Buffer`s and `Image`s can be used to store data on memory accessible from the GPU (or
//!   Vulkan implementation). Buffers are usually used to store vertices, lights, etc. or
//!   arbitrary data, while images are used to store textures or multi-dimensional data.
//!
//! - In order to show something on the screen, you need a `Swapchain`. A `Swapchain` contains a
//!   special `Image` that corresponds to the content of the window or the monitor. When you
//!   *present* a swapchain, the content of that special image is shown on the screen.
//!
//! - `ComputePipeline`s and `GraphicsPipeline`s describe the way the GPU must perform a certain
//!   operation. `Shader`s are programs that the GPU will execute as part of a pipeline.
//!
//! - `RenderPass`es and `Framebuffer`s describe on which attachments the implementation must draw
//!   on. They are only used for graphical operations.
//!
//! - In order to ask the GPU to do something, you must create a `CommandBuffer`. A `CommandBuffer`
//!   contains a list of commands that the GPU must perform. This can include copies between
//!   buffers, compute operations, or graphics operations. For the work to start, the
//!   `CommandBuffer` must then be submitted to a `Queue`, which is obtained when you create
//!   the `Device`.
//!

//#![warn(missing_docs)]        // TODO: activate
#![allow(dead_code)]            // TODO: remove
#![allow(unused_variables)]     // TODO: remove

#[macro_use]
extern crate lazy_static;
extern crate shared_library;

#[macro_use]
mod tests;

mod features;
mod version;

pub mod buffer;
pub mod command_buffer;
pub mod device;
pub mod formats;
pub mod framebuffer;
pub mod image;
pub mod instance;
pub mod memory;
pub mod pipeline;
//pub mod query;
pub mod sampler;
pub mod shader;
pub mod swapchain;
pub mod sync;

use std::error;
use std::fmt;
use std::mem;
use std::path::Path;

mod vk {
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_snake_case)]
    #![allow(non_camel_case_types)]
    include!(concat!(env!("OUT_DIR"), "/vk_bindings.rs"));
}

lazy_static! {
    static ref VK_LIB: shared_library::dynamic_library::DynamicLibrary = {
        #[cfg(windows)] fn get_path() -> &'static Path { Path::new("vulkan-1.dll") }
        #[cfg(unix)] fn get_path() -> &'static Path { Path::new("libvulkan-1.so") }
        let path = get_path();
        shared_library::dynamic_library::DynamicLibrary::open(Some(path)).unwrap()
    };

    static ref VK_STATIC: vk::Static = {
        vk::Static::load(|name| unsafe {
            VK_LIB.symbol(name.to_str().unwrap()).unwrap()      // TODO: error handling
        })
    };

    static ref VK_ENTRY: vk::EntryPoints = {
        vk::EntryPoints::load(|name| unsafe {
            mem::transmute(VK_STATIC.GetInstanceProcAddr(0, name.as_ptr()))
        })
    };
}

/// Gives access to the internals of an object.
trait VulkanObject {
    /// The type of the object.
    type Object;

    /// Returns a reference to the object.
    fn internal_object(&self) -> Self::Object;
}

/// Gives access to the Vulkan function pointers stored in this object.
trait VulkanPointers {
    /// The struct that provides access to the function pointers.
    type Pointers;

    // Returns a reference to the pointers.
    fn pointers(&self) -> &Self::Pointers;
}

/// Error type returned by most Vulkan functions.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OomError {
    /// There is no memory available on the host (ie. the CPU, RAM, etc.).
    OutOfHostMemory,
    /// There is no memory available on the device (ie. video memory).
    OutOfDeviceMemory,
}

impl error::Error for OomError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            OomError::OutOfHostMemory => "no memory available on the host",
            OomError::OutOfDeviceMemory => "no memory available on the graphical device",
        }
    }
}

impl fmt::Display for OomError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for OomError {
    #[inline]
    fn from(err: Error) -> OomError {
        match err {
            Error::OutOfHostMemory => OomError::OutOfHostMemory,
            Error::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

/// All possible success codes returned by any Vulkan function.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
enum Success {
    Success = vk::SUCCESS,
    NotReady = vk::NOT_READY,
    Timeout = vk::TIMEOUT,
    EventSet = vk::EVENT_SET,
    EventReset = vk::EVENT_RESET,
    Incomplete = vk::INCOMPLETE,
    Suboptimal = vk::SUBOPTIMAL_KHR,
}

/// All possible errors returned by any Vulkan function.
///
/// This type is not public. Instead all public error types should implement `From<Error>` and
/// panic for error code that arent supposed to happen.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
#[doc(hidden)]      // TODO: this is necessary because of the stupid visibility rules in rustc
pub enum Error {
    OutOfHostMemory = vk::ERROR_OUT_OF_HOST_MEMORY,
    OutOfDeviceMemory = vk::ERROR_OUT_OF_DEVICE_MEMORY,
    InitializationFailed = vk::ERROR_INITIALIZATION_FAILED,
    DeviceLost = vk::ERROR_DEVICE_LOST,
    MemoryMapFailed = vk::ERROR_MEMORY_MAP_FAILED,
    LayerNotPresent = vk::ERROR_LAYER_NOT_PRESENT,
    ExtensionNotPresent = vk::ERROR_EXTENSION_NOT_PRESENT,
    FeatureNotPresent = vk::ERROR_FEATURE_NOT_PRESENT,
    IncompatibleDriver = vk::ERROR_INCOMPATIBLE_DRIVER,
    TooManyObjects = vk::ERROR_TOO_MANY_OBJECTS,
    FormatNotSupported = vk::ERROR_FORMAT_NOT_SUPPORTED,
    SurfaceLost = vk::ERROR_SURFACE_LOST_KHR,
    NativeWindowInUse = vk::ERROR_NATIVE_WINDOW_IN_USE_KHR,
    OutOfDate = vk::ERROR_OUT_OF_DATE_KHR,
    IncompatibleDisplay = vk::ERROR_INCOMPATIBLE_DISPLAY_KHR,
    ValidationFailed = vk::ERROR_VALIDATION_FAILED_EXT,
}

/// Checks whether the result returned correctly.
fn check_errors(result: vk::Result) -> Result<Success, Error> {
    match result {
        vk::SUCCESS => Ok(Success::Success),
        vk::NOT_READY => Ok(Success::NotReady),
        vk::TIMEOUT => Ok(Success::Timeout),
        vk::EVENT_SET => Ok(Success::EventSet),
        vk::EVENT_RESET => Ok(Success::EventReset),
        vk::INCOMPLETE => Ok(Success::Incomplete),
        vk::ERROR_OUT_OF_HOST_MEMORY => Err(Error::OutOfHostMemory),
        vk::ERROR_OUT_OF_DEVICE_MEMORY => Err(Error::OutOfDeviceMemory),
        vk::ERROR_INITIALIZATION_FAILED => Err(Error::InitializationFailed),
        vk::ERROR_DEVICE_LOST => Err(Error::DeviceLost),
        vk::ERROR_MEMORY_MAP_FAILED => Err(Error::MemoryMapFailed),
        vk::ERROR_LAYER_NOT_PRESENT => Err(Error::LayerNotPresent),
        vk::ERROR_EXTENSION_NOT_PRESENT => Err(Error::ExtensionNotPresent),
        vk::ERROR_FEATURE_NOT_PRESENT => Err(Error::FeatureNotPresent),
        vk::ERROR_INCOMPATIBLE_DRIVER => Err(Error::IncompatibleDriver),
        vk::ERROR_TOO_MANY_OBJECTS => Err(Error::TooManyObjects),
        vk::ERROR_FORMAT_NOT_SUPPORTED => Err(Error::FormatNotSupported),
        vk::ERROR_SURFACE_LOST_KHR => Err(Error::SurfaceLost),
        vk::ERROR_NATIVE_WINDOW_IN_USE_KHR => Err(Error::NativeWindowInUse),
        vk::SUBOPTIMAL_KHR => Ok(Success::Suboptimal),
        vk::ERROR_OUT_OF_DATE_KHR => Err(Error::OutOfDate),
        vk::ERROR_INCOMPATIBLE_DISPLAY_KHR => Err(Error::IncompatibleDisplay),
        vk::ERROR_VALIDATION_FAILED_EXT => Err(Error::ValidationFailed),
        _ => unreachable!("Unexpected error code returned by Vulkan")
    }
}
<commit_msg>Add VulkanObjectU64 and VulkanObjectUsize<commit_after>//!
//! # Brief summary of Vulkan
//!
//! - The `Instance` object is the API entry point. It is the first object you must create before
//!   starting to use Vulkan.
//!
//! - The `PhysicalDevice` object represents an implementation of Vulkan available on the system
//!   (eg. a graphics card, a CPU implementation, multiple graphics card working together, etc.).
//!   Physical devices can be enumerated from an instance with `PhysicalDevice::enumerate()`.
//!
//! - Once you have chosen a physical device to use, you must a `Device` object from it. The
//!   `Device` is another very important object, as it represents an open channel of
//!   communicaton with the physical device.
//!
//! - `Buffer`s and `Image`s can be used to store data on memory accessible from the GPU (or
//!   Vulkan implementation). Buffers are usually used to store vertices, lights, etc. or
//!   arbitrary data, while images are used to store textures or multi-dimensional data.
//!
//! - In order to show something on the screen, you need a `Swapchain`. A `Swapchain` contains a
//!   special `Image` that corresponds to the content of the window or the monitor. When you
//!   *present* a swapchain, the content of that special image is shown on the screen.
//!
//! - `ComputePipeline`s and `GraphicsPipeline`s describe the way the GPU must perform a certain
//!   operation. `Shader`s are programs that the GPU will execute as part of a pipeline.
//!
//! - `RenderPass`es and `Framebuffer`s describe on which attachments the implementation must draw
//!   on. They are only used for graphical operations.
//!
//! - In order to ask the GPU to do something, you must create a `CommandBuffer`. A `CommandBuffer`
//!   contains a list of commands that the GPU must perform. This can include copies between
//!   buffers, compute operations, or graphics operations. For the work to start, the
//!   `CommandBuffer` must then be submitted to a `Queue`, which is obtained when you create
//!   the `Device`.
//!

//#![warn(missing_docs)]        // TODO: activate
#![allow(dead_code)]            // TODO: remove
#![allow(unused_variables)]     // TODO: remove

#[macro_use]
extern crate lazy_static;
extern crate shared_library;

#[macro_use]
mod tests;

mod features;
mod version;

pub mod buffer;
pub mod command_buffer;
pub mod device;
pub mod formats;
pub mod framebuffer;
pub mod image;
pub mod instance;
pub mod memory;
pub mod pipeline;
//pub mod query;
pub mod sampler;
pub mod shader;
pub mod swapchain;
pub mod sync;

use std::error;
use std::fmt;
use std::mem;
use std::path::Path;

mod vk {
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_snake_case)]
    #![allow(non_camel_case_types)]
    include!(concat!(env!("OUT_DIR"), "/vk_bindings.rs"));
}

lazy_static! {
    static ref VK_LIB: shared_library::dynamic_library::DynamicLibrary = {
        #[cfg(windows)] fn get_path() -> &'static Path { Path::new("vulkan-1.dll") }
        #[cfg(unix)] fn get_path() -> &'static Path { Path::new("libvulkan-1.so") }
        let path = get_path();
        shared_library::dynamic_library::DynamicLibrary::open(Some(path)).unwrap()
    };

    static ref VK_STATIC: vk::Static = {
        vk::Static::load(|name| unsafe {
            VK_LIB.symbol(name.to_str().unwrap()).unwrap()      // TODO: error handling
        })
    };

    static ref VK_ENTRY: vk::EntryPoints = {
        vk::EntryPoints::load(|name| unsafe {
            mem::transmute(VK_STATIC.GetInstanceProcAddr(0, name.as_ptr()))
        })
    };
}

/// Gives access to the internals of an object.
trait VulkanObject {
    /// The type of the object.
    type Object;

    /// Returns a reference to the object.
    fn internal_object(&self) -> Self::Object;
}

// TODO: remove eventually
// https://github.com/rust-lang/rust/issues/29328
trait VulkanObjectU64 { fn internal_object(&self) -> u64; }
impl<T> VulkanObjectU64 for T where T: VulkanObject<Object = u64> {
    #[inline]
    fn internal_object(&self) -> u64 { VulkanObject::internal_object(self) }
}
// TODO: remove eventually
// https://github.com/rust-lang/rust/issues/29328
trait VulkanObjectUsize { fn internal_object(&self) -> usize; }
impl<T> VulkanObjectUsize for T where T: VulkanObject<Object = usize> {
    #[inline]
    fn internal_object(&self) -> usize { VulkanObject::internal_object(self) }
}

/// Gives access to the Vulkan function pointers stored in this object.
trait VulkanPointers {
    /// The struct that provides access to the function pointers.
    type Pointers;

    // Returns a reference to the pointers.
    fn pointers(&self) -> &Self::Pointers;
}

/// Error type returned by most Vulkan functions.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OomError {
    /// There is no memory available on the host (ie. the CPU, RAM, etc.).
    OutOfHostMemory,
    /// There is no memory available on the device (ie. video memory).
    OutOfDeviceMemory,
}

impl error::Error for OomError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            OomError::OutOfHostMemory => "no memory available on the host",
            OomError::OutOfDeviceMemory => "no memory available on the graphical device",
        }
    }
}

impl fmt::Display for OomError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for OomError {
    #[inline]
    fn from(err: Error) -> OomError {
        match err {
            Error::OutOfHostMemory => OomError::OutOfHostMemory,
            Error::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

/// All possible success codes returned by any Vulkan function.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
enum Success {
    Success = vk::SUCCESS,
    NotReady = vk::NOT_READY,
    Timeout = vk::TIMEOUT,
    EventSet = vk::EVENT_SET,
    EventReset = vk::EVENT_RESET,
    Incomplete = vk::INCOMPLETE,
    Suboptimal = vk::SUBOPTIMAL_KHR,
}

/// All possible errors returned by any Vulkan function.
///
/// This type is not public. Instead all public error types should implement `From<Error>` and
/// panic for error code that arent supposed to happen.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
#[doc(hidden)]      // TODO: this is necessary because of the stupid visibility rules in rustc
pub enum Error {
    OutOfHostMemory = vk::ERROR_OUT_OF_HOST_MEMORY,
    OutOfDeviceMemory = vk::ERROR_OUT_OF_DEVICE_MEMORY,
    InitializationFailed = vk::ERROR_INITIALIZATION_FAILED,
    DeviceLost = vk::ERROR_DEVICE_LOST,
    MemoryMapFailed = vk::ERROR_MEMORY_MAP_FAILED,
    LayerNotPresent = vk::ERROR_LAYER_NOT_PRESENT,
    ExtensionNotPresent = vk::ERROR_EXTENSION_NOT_PRESENT,
    FeatureNotPresent = vk::ERROR_FEATURE_NOT_PRESENT,
    IncompatibleDriver = vk::ERROR_INCOMPATIBLE_DRIVER,
    TooManyObjects = vk::ERROR_TOO_MANY_OBJECTS,
    FormatNotSupported = vk::ERROR_FORMAT_NOT_SUPPORTED,
    SurfaceLost = vk::ERROR_SURFACE_LOST_KHR,
    NativeWindowInUse = vk::ERROR_NATIVE_WINDOW_IN_USE_KHR,
    OutOfDate = vk::ERROR_OUT_OF_DATE_KHR,
    IncompatibleDisplay = vk::ERROR_INCOMPATIBLE_DISPLAY_KHR,
    ValidationFailed = vk::ERROR_VALIDATION_FAILED_EXT,
}

/// Checks whether the result returned correctly.
fn check_errors(result: vk::Result) -> Result<Success, Error> {
    match result {
        vk::SUCCESS => Ok(Success::Success),
        vk::NOT_READY => Ok(Success::NotReady),
        vk::TIMEOUT => Ok(Success::Timeout),
        vk::EVENT_SET => Ok(Success::EventSet),
        vk::EVENT_RESET => Ok(Success::EventReset),
        vk::INCOMPLETE => Ok(Success::Incomplete),
        vk::ERROR_OUT_OF_HOST_MEMORY => Err(Error::OutOfHostMemory),
        vk::ERROR_OUT_OF_DEVICE_MEMORY => Err(Error::OutOfDeviceMemory),
        vk::ERROR_INITIALIZATION_FAILED => Err(Error::InitializationFailed),
        vk::ERROR_DEVICE_LOST => Err(Error::DeviceLost),
        vk::ERROR_MEMORY_MAP_FAILED => Err(Error::MemoryMapFailed),
        vk::ERROR_LAYER_NOT_PRESENT => Err(Error::LayerNotPresent),
        vk::ERROR_EXTENSION_NOT_PRESENT => Err(Error::ExtensionNotPresent),
        vk::ERROR_FEATURE_NOT_PRESENT => Err(Error::FeatureNotPresent),
        vk::ERROR_INCOMPATIBLE_DRIVER => Err(Error::IncompatibleDriver),
        vk::ERROR_TOO_MANY_OBJECTS => Err(Error::TooManyObjects),
        vk::ERROR_FORMAT_NOT_SUPPORTED => Err(Error::FormatNotSupported),
        vk::ERROR_SURFACE_LOST_KHR => Err(Error::SurfaceLost),
        vk::ERROR_NATIVE_WINDOW_IN_USE_KHR => Err(Error::NativeWindowInUse),
        vk::SUBOPTIMAL_KHR => Ok(Success::Suboptimal),
        vk::ERROR_OUT_OF_DATE_KHR => Err(Error::OutOfDate),
        vk::ERROR_INCOMPATIBLE_DISPLAY_KHR => Err(Error::IncompatibleDisplay),
        vk::ERROR_VALIDATION_FAILED_EXT => Err(Error::ValidationFailed),
        _ => unreachable!("Unexpected error code returned by Vulkan")
    }
}
<|endoftext|>


<commit_before>#![feature(path, env)]
extern crate gcc;

use std::path::PathBuf;
use std::env;

const LIB_NAME: &'static str = "libctxswtch.a";

fn main() {
    let arch =
        if cfg!(target_arch = "x86_64") {
            "x86_64"
        } else if cfg!(target_arch = "i686") {
            "i686"
        } else if cfg!(target_arch = "arm") {
            "arm"
        } else if cfg!(target_arch = "mips") {
            "mips"
        } else if cfg!(target_arch = "mipsel") {
            "mipsel"
        } else {
            panic!("Unsupported architecture: {}", env::var("TARGET").unwrap());
        };
    let src_path = &["src", "asm", arch, "_context.S"].iter().collect::<PathBuf>();
    gcc::compile_library(LIB_NAME, &[src_path.to_str().unwrap()]);

    println!("cargo:rustc-flags=-l ctxswtch:static");
}
<commit_msg>seems like the rustc-flags output is no need<commit_after>#![feature(path, env)]
extern crate gcc;

use std::path::PathBuf;
use std::env;

const LIB_NAME: &'static str = "libctxswtch.a";

fn main() {
    let arch =
        if cfg!(target_arch = "x86_64") {
            "x86_64"
        } else if cfg!(target_arch = "i686") {
            "i686"
        } else if cfg!(target_arch = "arm") {
            "arm"
        } else if cfg!(target_arch = "mips") {
            "mips"
        } else if cfg!(target_arch = "mipsel") {
            "mipsel"
        } else {
            panic!("Unsupported architecture: {}", env::var("TARGET").unwrap());
        };
    let src_path = &["src", "asm", arch, "_context.S"].iter().collect::<PathBuf>();
    gcc::compile_library(LIB_NAME, &[src_path.to_str().unwrap()]);

// seems like this line is no need actually
//    println!("cargo:rustc-flags=-l ctxswtch:static");
}
<|endoftext|>


<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use energy::{Potential, PairPotential};

/// Alternative energy and forces computation.
///
/// The `Computation` trait represent an alternative way to compute a given
/// potential. For example using interpolation on a table or on a grid, from a
/// Fourrier deecompostion, *etc.*
pub trait Computation: Sync + Send {
    /// Compute the energy value at `r`
    fn compute_energy(&self, r: f64) -> f64;

    /// Compute the force value at `r`
    fn compute_force(&self, r: f64) -> f64;
}

impl<P: Computation + Clone + 'static> Potential for P {
    #[inline] fn energy(&self, r:f64) -> f64 {
        self.compute_energy(r)
    }

    #[inline] fn force(&self, r:f64) -> f64 {
        self.compute_force(r)
    }
}

/// Computation of a potential using tabulated values.
///
/// This can be faster than direct computation for smooth potentials, but will
/// uses more memory and be less precise than direct computation. Values are
/// tabulated in the `[0, max)` range, and a cutoff is applied after `max`.
/// Energy is shifted to ensure `E(max) = 0`
#[derive(Clone)]
pub struct TableComputation {
    /// Step for tabulated value. `energy_table[i]`/`force_table[i]` contains
    /// energy/force at `r = i * delta`
    delta: f64,
    /// Tabulated potential
    energy_table: Vec<f64>,
    /// Tabulated compute_force
    force_table: Vec<f64>,
}

impl TableComputation {
    /// Create a new `TableComputation` for `potential`, with `size` points and
    /// a maximum value of `max`.
    pub fn new(potential: &PairPotential, size: usize, max:f64) -> TableComputation {
        let delta = max / (size as f64);
        let energy_shift = potential.energy(max);
        let mut energy_table = Vec::with_capacity(size);
        let mut force_table = Vec::with_capacity(size);
        for i in 0..size {
            let pos = i as f64 * delta;
            energy_table.push(potential.energy(pos) - energy_shift);
            force_table.push(potential.force(pos));
        }
        TableComputation {
            delta: delta,
            energy_table: energy_table,
            force_table: force_table
        }
    }
}

impl Computation for TableComputation {
    fn compute_energy(&self, r: f64) -> f64 {
        debug_assert!(self.energy_table.len() == self.force_table.len());
        let bin = f64::floor(r / self.delta) as usize;
        if bin < self.energy_table.len() - 1 {
            let dx = r - (bin as f64) * self.delta;
            let slope = (self.energy_table[bin + 1] - self.energy_table[bin]) / self.delta;
            return self.energy_table[bin] + dx * slope;
        } else {
            return 0.0;
        }
    }

    fn compute_force(&self, r: f64) -> f64 {
        debug_assert!(self.energy_table.len() == self.force_table.len());
        let bin = f64::floor(r / self.delta) as usize;
        if bin < self.force_table.len() - 1 {
            let dx = r - (bin as f64) * self.delta;
            let slope = (self.force_table[bin + 1] - self.force_table[bin]) / self.delta;
            return self.force_table[bin] + dx * slope;
        } else {
            return 0.0;
        }
    }
}

impl PairPotential for TableComputation {}

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

    #[test]
    fn table() {
        let table = TableComputation::new(&Harmonic{k: 50.0, x0: 2.0}, 1000, 4.0);

        assert_eq!(table.compute_energy(2.5), -93.75);
        assert_eq!(table.compute_force(2.5), -25.0);

        // Check that the table is defined up to the cutoff value
        let delta = 4.0 / 1000.0;
        assert_eq!(table.compute_energy(4.0 - 2.0 * delta), -0.7984000000000009);
        assert_eq!(table.compute_force(4.0 - 2.0 * delta), -99.6);

        assert_eq!(table.compute_energy(4.0 - delta), 0.0);
        assert_eq!(table.compute_force(4.0 - delta), 0.0);

        assert_eq!(table.compute_energy(4.0), 0.0);
        assert_eq!(table.compute_force(4.0), 0.0);

        assert_eq!(table.compute_energy(4.1), 0.0);
        assert_eq!(table.compute_force(4.1), 0.0);
    }
}
<commit_msg>[doc] Example for the potential Computation<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use energy::{Potential, PairPotential};

/// Alternative energy and forces computation.
///
/// The `Computation` trait represent an alternative way to compute a given
/// potential. For example using interpolation on a table or on a grid, from a
/// Fourrier decompostion, *etc.*
///
/// # Examples
///
/// ```
/// # use lumol::energy::Potential;
/// use lumol::energy::Computation;
/// use lumol::energy::Harmonic;
///
/// /// This is just a thin wrapper logging everytime the `energy/force`
/// /// methods are called.
/// #[derive(Clone)]
/// struct LoggingComputation<T: Potential>(T);
///
/// impl<T: Potential> Computation for LoggingComputation<T> {
///     fn compute_energy(&self, r: f64) -> f64 {
///         println!("Called energy");
///         self.0.energy(r)
///     }
///
///     fn compute_force(&self, r: f64) -> f64 {
///         println!("Called force");
///         self.0.force(r)
///     }
/// }
///
/// let potential = Harmonic{x0: 0.5, k: 4.2};
/// let computation = LoggingComputation(potential.clone());
///
/// assert_eq!(computation.energy(1.0), potential.energy(1.0));
/// assert_eq!(computation.force(2.0), potential.force(2.0));
/// ```
pub trait Computation: Sync + Send {
    /// Compute the energy value at `r`
    fn compute_energy(&self, r: f64) -> f64;

    /// Compute the force value at `r`
    fn compute_force(&self, r: f64) -> f64;
}

impl<P: Computation + Clone + 'static> Potential for P {
    #[inline] fn energy(&self, r:f64) -> f64 {
        self.compute_energy(r)
    }

    #[inline] fn force(&self, r:f64) -> f64 {
        self.compute_force(r)
    }
}

/// Computation of a potential using tabulated values.
///
/// This can be faster than direct computation for smooth potentials, but will
/// uses more memory and be less precise than direct computation. Values are
/// tabulated in the `[0, max)` range, and a cutoff is applied after `max`.
/// Energy is shifted to ensure `E(max) = 0`
#[derive(Clone)]
pub struct TableComputation {
    /// Step for tabulated value. `energy_table[i]`/`force_table[i]` contains
    /// energy/force at `r = i * delta`
    delta: f64,
    /// Tabulated potential
    energy_table: Vec<f64>,
    /// Tabulated compute_force
    force_table: Vec<f64>,
}

impl TableComputation {
    /// Create a new `TableComputation` for `potential`, with `size` points and
    /// a maximum value of `max`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::energy::Potential;
    /// use lumol::energy::TableComputation;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Harmonic{x0: 0.5, k: 4.2};
    /// let table = TableComputation::new(&potential, 1000, 2.0);
    ///
    /// assert_eq!(table.energy(1.0), -4.2);
    /// assert_eq!(table.energy(3.0), 0.0);
    /// ```
    pub fn new(potential: &PairPotential, size: usize, max:f64) -> TableComputation {
        let delta = max / (size as f64);
        let energy_shift = potential.energy(max);
        let mut energy_table = Vec::with_capacity(size);
        let mut force_table = Vec::with_capacity(size);
        for i in 0..size {
            let pos = i as f64 * delta;
            energy_table.push(potential.energy(pos) - energy_shift);
            force_table.push(potential.force(pos));
        }
        TableComputation {
            delta: delta,
            energy_table: energy_table,
            force_table: force_table
        }
    }
}

impl Computation for TableComputation {
    fn compute_energy(&self, r: f64) -> f64 {
        debug_assert!(self.energy_table.len() == self.force_table.len());
        let bin = f64::floor(r / self.delta) as usize;
        if bin < self.energy_table.len() - 1 {
            let dx = r - (bin as f64) * self.delta;
            let slope = (self.energy_table[bin + 1] - self.energy_table[bin]) / self.delta;
            return self.energy_table[bin] + dx * slope;
        } else {
            return 0.0;
        }
    }

    fn compute_force(&self, r: f64) -> f64 {
        debug_assert!(self.energy_table.len() == self.force_table.len());
        let bin = f64::floor(r / self.delta) as usize;
        if bin < self.force_table.len() - 1 {
            let dx = r - (bin as f64) * self.delta;
            let slope = (self.force_table[bin + 1] - self.force_table[bin]) / self.delta;
            return self.force_table[bin] + dx * slope;
        } else {
            return 0.0;
        }
    }
}

impl PairPotential for TableComputation {}

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

    #[test]
    fn table() {
        let table = TableComputation::new(&Harmonic{k: 50.0, x0: 2.0}, 1000, 4.0);

        assert_eq!(table.compute_energy(2.5), -93.75);
        assert_eq!(table.compute_force(2.5), -25.0);

        // Check that the table is defined up to the cutoff value
        let delta = 4.0 / 1000.0;
        assert_eq!(table.compute_energy(4.0 - 2.0 * delta), -0.7984000000000009);
        assert_eq!(table.compute_force(4.0 - 2.0 * delta), -99.6);

        assert_eq!(table.compute_energy(4.0 - delta), 0.0);
        assert_eq!(table.compute_force(4.0 - delta), 0.0);

        assert_eq!(table.compute_energy(4.0), 0.0);
        assert_eq!(table.compute_force(4.0), 0.0);

        assert_eq!(table.compute_energy(4.1), 0.0);
        assert_eq!(table.compute_force(4.1), 0.0);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Eq;
use std::fmt::Display;
use std::iter::FromIterator;

trait Parser<T: Display + Eq, E>: Sized {
    fn preview(&self) -> Option<&T>;
    fn consume(&mut self) -> Option<T>;
    fn current_pos(&self) -> (i32, i32);
    fn error<S: Into<String>>(&self, message: S) -> E;

    fn save(&mut self);
    fn load(&mut self);

    fn next(&mut self) -> Result<T, E> {
        self.consume().ok_or(self.error("unexpected eof"))
    }

    fn predicate<F>(&mut self, pred: F) -> Result<T, E>
        where F: Fn(&T) -> bool
    {
        let x = try!(self.next());
        if pred(&x) {
            Ok(x)
        } else {
            Err(self.error(format!("unexpected token {}", x)))
        }
    }

    fn atom(&mut self, expected: T) -> Result<T, E> {
        let x = try!(self.next());
        if x == expected {
            Ok(x)
        } else {
            Err(self.error(format!("unexpected token {}, expected {}", x, expected)))
        }
    }

    fn string<S, O>(&mut self, s: S) -> Result<O, E>
        where S: IntoIterator<Item = T>,
              O: FromIterator<T>
    {
        let mut res: Vec<T> = Vec::new();
        for c in s {
            match self.atom(c) {
                Ok(x) => res.push(x),
                Err(err) => return Err(err),
            }
        }
        Ok(O::from_iter(res))
    }

    fn try<O, F>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<O, E>
    {
        self.save();
        parser(self).map_err(|x| {
                                 self.load();
                                 x
                             })
    }

    fn choose<O>(&mut self, parsers: &[&Fn(&mut Self) -> Result<O, E>]) -> Result<O, E> {
        for parser in parsers {
            match self.try(parser) {
                Ok(x) => return Ok(x),
                Err(_) => continue,
            }
        }

        Err(self.error(match self.preview() {
                           Some(x) => format!("unexpected token {}", x),
                           None => String::from("unexpected eof"),
                       }))
    }

    fn many<X, F, O>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<X, E>,
              O: FromIterator<X>
    {
        let mut res: Vec<X> = Vec::new();
        loop {
            match self.try(&parser) {
                Ok(x) => res.push(x),
                Err(_) => break,
            }
        }
        Ok(O::from_iter(res))
    }

    fn many1<X, F, O>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<X, E>,
              O: FromIterator<X>
    {
        let mut res: Vec<X> = Vec::new();
        res.push(try!(parser(self)));
        loop {
            match self.try(&parser) {
                Ok(x) => res.push(x),
                Err(_) => break,
            }
        }
        Ok(O::from_iter(res))
    }

    fn optional<X, F>(&mut self, parser: F)
        where F: Fn(&mut Self) -> Result<X, E>
    {
        self.try(parser);
    }
}

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

    struct TP {
        input: Vec<i32>,
        cursor: usize,
        saved_cursor: usize,
    }

    impl TP {
        fn new(input: &[i32]) -> TP {
            TP {
                input: input.to_vec(),
                cursor: 0,
                saved_cursor: 0,
            }
        }
    }

    impl Parser<i32, String> for TP {
        fn consume(&mut self) -> Option<i32> {
            match self.input.get(self.cursor) {
                Some(x) => {
                    self.cursor += 1;
                    Some(x.clone())
                }
                None => None,
            }
        }

        fn preview(&self) -> Option<&i32> {
            self.input.get(self.cursor)
        }

        fn current_pos(&self) -> (i32, i32) {
            (0, 0)
        }

        fn error<S: Into<String>>(&self, message: S) -> String {
            message.into()
        }

        fn save(&mut self) {
            self.saved_cursor = self.cursor;
        }

        fn load(&mut self) {
            self.cursor = self.saved_cursor;
        }
    }

    type TPR = Result<Vec<i32>, String>;

    fn err<T>(m: &str) -> Result<T, String> {
        Err(String::from(m))
    }

    #[test]
    fn next_success() {
        let mut p = TP::new(&[1, 2, 3]);
        assert_eq!(p.next(), Ok(1));
        assert_eq!(p.next(), Ok(2));
        assert_eq!(p.next(), Ok(3));
    }

    #[test]
    fn next_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.next(), err("unexpected eof"));
    }

    #[test]
    fn predicate_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(2));
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(4));
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(6));
    }

    #[test]
    fn predicate_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected eof"));
    }

    #[test]
    fn predicate_fail_not_satisfy() {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected token 3"));
    }

    #[test]
    fn atom_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.atom(2), Ok(2));
        assert_eq!(p.atom(4), Ok(4));
        assert_eq!(p.atom(6), Ok(6));
    }

    #[test]
    fn atom_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.atom(2), err("unexpected eof"));
    }

    #[test]
    fn atom_fail_not_expected() {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(p.atom(3), Ok(3));
        assert_eq!(p.atom(4), err("unexpected token 5, expected 4"));
    }

    #[test]
    fn string_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.string(vec![2, 4, 6]), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn string_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.string(vec![2, 4, 6]) as TPR, err("unexpected eof"));
    }

    #[test]
    fn string_fail_not_expected() {
        let mut p = TP::new(&[2, 5, 6]);
        assert_eq!(p.string(vec![2, 4, 6]) as TPR,
                   err("unexpected token 5, expected 4"));
    }

    #[test]
    fn try_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn try_fail_recover() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.try(|p| p.string(vec![2, 4, 7])) as TPR,
                   err("unexpected token 6, expected 7"));
        assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn choose_success() {
        let mut p = TP::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 7]),
                              &|p| p.string(vec![4, 5, 6])]),
                   Ok(vec![1, 2, 3]));
    }

    #[test]
    fn choose_success_with_recover() {
        let mut p = TP::new(&[4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]),
                   Ok(vec![4, 5, 6]));
    }

    #[test]
    fn choose_fail_no_match() {
        let mut p = TP::new(&[5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]) as TPR,
                   err("unexpected token 5"));
    }

    #[test]
    fn choose_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]) as TPR,
                   err("unexpected eof"));
    }

    #[test]
    fn many_success() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[1, 2, 3, 4]).many(&lt5), Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many(&lt5),
                   Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many(&lt5), Ok(vec![4]));
        assert_eq!(TP::new(&[5, 6, 7, 8]).many(&lt5), Ok(vec![]));
    }

    #[test]
    fn many1_success() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[1, 2, 3, 4]).many1(&lt5), Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many1(&lt5),
                   Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many1(&lt5), Ok(vec![4]));
    }

    #[test]
    fn many1_fail() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[5, 6, 7, 8]).many1(&lt5) as TPR,
                   err("unexpected token 5"));
    }

    #[test]
    fn optional_success() {
        let mut p = TP::new(&[1, 2, 3, 4, 5]);
        p.optional(|p| p.atom(1));
        assert_eq!(p.string(vec![2, 3, 4]), Ok(vec![2, 3, 4]));
    }

    #[test]
    fn optional_success_without_matching() {
        let mut p = TP::new(&[1, 2, 3, 4, 5]);
        p.optional(|p| p.atom(2));
        assert_eq!(p.string(vec![1, 2, 3]), Ok(vec![1, 2, 3]));
    }
}
<commit_msg>Remove ignored result warning<commit_after>use std::cmp::Eq;
use std::fmt::Display;
use std::iter::FromIterator;

trait Parser<T: Display + Eq, E>: Sized {
    fn preview(&self) -> Option<&T>;
    fn consume(&mut self) -> Option<T>;
    fn current_pos(&self) -> (i32, i32);
    fn error<S: Into<String>>(&self, message: S) -> E;

    fn save(&mut self);
    fn load(&mut self);

    fn next(&mut self) -> Result<T, E> {
        self.consume().ok_or(self.error("unexpected eof"))
    }

    fn predicate<F>(&mut self, pred: F) -> Result<T, E>
        where F: Fn(&T) -> bool
    {
        let x = try!(self.next());
        if pred(&x) {
            Ok(x)
        } else {
            Err(self.error(format!("unexpected token {}", x)))
        }
    }

    fn atom(&mut self, expected: T) -> Result<T, E> {
        let x = try!(self.next());
        if x == expected {
            Ok(x)
        } else {
            Err(self.error(format!("unexpected token {}, expected {}", x, expected)))
        }
    }

    fn string<S, O>(&mut self, s: S) -> Result<O, E>
        where S: IntoIterator<Item = T>,
              O: FromIterator<T>
    {
        let mut res: Vec<T> = Vec::new();
        for c in s {
            match self.atom(c) {
                Ok(x) => res.push(x),
                Err(err) => return Err(err),
            }
        }
        Ok(O::from_iter(res))
    }

    fn try<O, F>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<O, E>
    {
        self.save();
        parser(self).map_err(|x| {
                                 self.load();
                                 x
                             })
    }

    fn choose<O>(&mut self, parsers: &[&Fn(&mut Self) -> Result<O, E>]) -> Result<O, E> {
        for parser in parsers {
            match self.try(parser) {
                Ok(x) => return Ok(x),
                Err(_) => continue,
            }
        }

        Err(self.error(match self.preview() {
                           Some(x) => format!("unexpected token {}", x),
                           None => String::from("unexpected eof"),
                       }))
    }

    fn many<X, F, O>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<X, E>,
              O: FromIterator<X>
    {
        let mut res: Vec<X> = Vec::new();
        loop {
            match self.try(&parser) {
                Ok(x) => res.push(x),
                Err(_) => break,
            }
        }
        Ok(O::from_iter(res))
    }

    fn many1<X, F, O>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<X, E>,
              O: FromIterator<X>
    {
        let mut res: Vec<X> = Vec::new();
        res.push(try!(parser(self)));
        loop {
            match self.try(&parser) {
                Ok(x) => res.push(x),
                Err(_) => break,
            }
        }
        Ok(O::from_iter(res))
    }

    fn optional<X, F>(&mut self, parser: F)
        where F: Fn(&mut Self) -> Result<X, E>
    {
        let _ = self.try(parser);
    }
}

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

    struct TP {
        input: Vec<i32>,
        cursor: usize,
        saved_cursor: usize,
    }

    impl TP {
        fn new(input: &[i32]) -> TP {
            TP {
                input: input.to_vec(),
                cursor: 0,
                saved_cursor: 0,
            }
        }
    }

    impl Parser<i32, String> for TP {
        fn consume(&mut self) -> Option<i32> {
            match self.input.get(self.cursor) {
                Some(x) => {
                    self.cursor += 1;
                    Some(x.clone())
                }
                None => None,
            }
        }

        fn preview(&self) -> Option<&i32> {
            self.input.get(self.cursor)
        }

        fn current_pos(&self) -> (i32, i32) {
            (0, 0)
        }

        fn error<S: Into<String>>(&self, message: S) -> String {
            message.into()
        }

        fn save(&mut self) {
            self.saved_cursor = self.cursor;
        }

        fn load(&mut self) {
            self.cursor = self.saved_cursor;
        }
    }

    type TPR = Result<Vec<i32>, String>;

    fn err<T>(m: &str) -> Result<T, String> {
        Err(String::from(m))
    }

    #[test]
    fn next_success() {
        let mut p = TP::new(&[1, 2, 3]);
        assert_eq!(p.next(), Ok(1));
        assert_eq!(p.next(), Ok(2));
        assert_eq!(p.next(), Ok(3));
    }

    #[test]
    fn next_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.next(), err("unexpected eof"));
    }

    #[test]
    fn predicate_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(2));
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(4));
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(6));
    }

    #[test]
    fn predicate_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected eof"));
    }

    #[test]
    fn predicate_fail_not_satisfy() {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected token 3"));
    }

    #[test]
    fn atom_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.atom(2), Ok(2));
        assert_eq!(p.atom(4), Ok(4));
        assert_eq!(p.atom(6), Ok(6));
    }

    #[test]
    fn atom_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.atom(2), err("unexpected eof"));
    }

    #[test]
    fn atom_fail_not_expected() {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(p.atom(3), Ok(3));
        assert_eq!(p.atom(4), err("unexpected token 5, expected 4"));
    }

    #[test]
    fn string_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.string(vec![2, 4, 6]), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn string_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.string(vec![2, 4, 6]) as TPR, err("unexpected eof"));
    }

    #[test]
    fn string_fail_not_expected() {
        let mut p = TP::new(&[2, 5, 6]);
        assert_eq!(p.string(vec![2, 4, 6]) as TPR,
                   err("unexpected token 5, expected 4"));
    }

    #[test]
    fn try_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn try_fail_recover() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.try(|p| p.string(vec![2, 4, 7])) as TPR,
                   err("unexpected token 6, expected 7"));
        assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn choose_success() {
        let mut p = TP::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 7]),
                              &|p| p.string(vec![4, 5, 6])]),
                   Ok(vec![1, 2, 3]));
    }

    #[test]
    fn choose_success_with_recover() {
        let mut p = TP::new(&[4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]),
                   Ok(vec![4, 5, 6]));
    }

    #[test]
    fn choose_fail_no_match() {
        let mut p = TP::new(&[5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]) as TPR,
                   err("unexpected token 5"));
    }

    #[test]
    fn choose_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]) as TPR,
                   err("unexpected eof"));
    }

    #[test]
    fn many_success() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[1, 2, 3, 4]).many(&lt5), Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many(&lt5),
                   Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many(&lt5), Ok(vec![4]));
        assert_eq!(TP::new(&[5, 6, 7, 8]).many(&lt5), Ok(vec![]));
    }

    #[test]
    fn many1_success() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[1, 2, 3, 4]).many1(&lt5), Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many1(&lt5),
                   Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many1(&lt5), Ok(vec![4]));
    }

    #[test]
    fn many1_fail() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[5, 6, 7, 8]).many1(&lt5) as TPR,
                   err("unexpected token 5"));
    }

    #[test]
    fn optional_success() {
        let mut p = TP::new(&[1, 2, 3, 4, 5]);
        p.optional(|p| p.atom(1));
        assert_eq!(p.string(vec![2, 3, 4]), Ok(vec![2, 3, 4]));
    }

    #[test]
    fn optional_success_without_matching() {
        let mut p = TP::new(&[1, 2, 3, 4, 5]);
        p.optional(|p| p.atom(2));
        assert_eq!(p.string(vec![1, 2, 3]), Ok(vec![1, 2, 3]));
    }
}
<|endoftext|>