<commit_before>pub use self::types::*;

use self::parse::*;
use clap::ArgMatches;
use coveralls_api::CiService;
use log::{error, info, warn};
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{Error, ErrorKind, Read};
use std::path::{Path, PathBuf};
use std::time::Duration;

mod parse;
pub mod types;

pub struct ConfigWrapper(pub Vec<Config>);

/// Specifies the current configuration tarpaulin is using.
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct Config {
    pub name: String,
    /// Path to the projects cargo manifest
    pub manifest: PathBuf,
    /// Path to a tarpaulin.toml config file
    pub config: Option<PathBuf>,
    /// Path to the projects cargo manifest
    pub root: Option<String>,
    /// Flag to also run tests with the ignored attribute
    pub run_ignored: bool,
    /// Flag to ignore test functions in coverage statistics
    pub ignore_tests: bool,
    /// Ignore panic macros in code.
    pub ignore_panics: bool,
    /// Flag to add a clean step when preparing the target project
    pub force_clean: bool,
    /// Verbose flag for printing information to the user
    pub verbose: bool,
    /// Debug flag for printing internal debugging information to the user
    pub debug: bool,
    /// Flag to count hits in coverage
    pub count: bool,
    /// Flag specifying to run line coverage (default)
    pub line_coverage: bool,
    /// Flag specifying to run branch coverage
    pub branch_coverage: bool,
    /// Directory to write output files
    pub output_directory: PathBuf,
    /// Key relating to coveralls service or repo
    pub coveralls: Option<String>,
    /// Enum representing CI tool used.
    pub ci_tool: Option<CiService>,
    /// Only valid if coveralls option is set. If coveralls option is set,
    /// as well as report_uri, then the report will be sent to this endpoint
    /// instead.
    pub report_uri: Option<String>,
    /// Forward unexpected signals back to the tracee. Used for tests which
    /// rely on signals to work.
    pub forward_signals: bool,
    /// Include all available features in target build
    pub all_features: bool,
    /// Do not include default features in target build
    pub no_default_features: bool,
    /// Build all packages in the workspace
    pub all: bool,
    /// Duration to wait before a timeout occurs
    pub test_timeout: Duration,
    /// Build in release mode
    pub release: bool,
    /// Build the tests only don't run coverage
    pub no_run: bool,
    /// Don't update `Cargo.lock`.
    pub locked: bool,
    /// Don't update `Cargo.lock` or any caches.
    pub frozen: bool,
    /// Directory for generated artifacts
    pub target_dir: Option<PathBuf>,
    /// Run tarpaulin on project without accessing the network
    pub offline: bool,
    /// Types of tests for tarpaulin to collect coverage on
    pub run_types: Vec<RunType>,
    /// Packages to include when building the target project
    pub packages: Vec<String>,
    /// Packages to exclude from testing
    pub exclude: Vec<String>,
    /// Files to exclude from testing in their compiled form
    #[serde(skip_deserializing, skip_serializing)]
    excluded_files: RefCell<Vec<Regex>>,
    /// Files to exclude from testing in uncompiled form (for serde)
    excluded_files_raw: Vec<String>,
    /// Varargs to be forwarded to the test executables.
    pub varargs: Vec<String>,
    /// Features to include in the target project build
    pub features: Vec<String>,
    /// Unstable cargo features to use
    pub unstable_features: Vec<String>,
    /// Output files to generate
    pub generate: Vec<OutputFile>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            name: String::new(),
            run_types: vec![RunType::Tests],
            manifest: default_manifest(),
            config: None,
            root: Default::default(),
            run_ignored: false,
            ignore_tests: false,
            ignore_panics: false,
            force_clean: false,
            verbose: false,
            debug: false,
            count: false,
            line_coverage: true,
            branch_coverage: false,
            generate: vec![],
            output_directory: Default::default(),
            coveralls: None,
            ci_tool: None,
            report_uri: None,
            forward_signals: false,
            no_default_features: false,
            features: vec![],
            unstable_features: vec![],
            all: false,
            packages: vec![],
            exclude: vec![],
            excluded_files: RefCell::new(vec![]),
            excluded_files_raw: vec![],
            varargs: vec![],
            test_timeout: Duration::from_secs(60),
            release: false,
            all_features: false,
            no_run: false,
            locked: false,
            frozen: false,
            target_dir: None,
            offline: false,
        }
    }
}

impl<'a> From<&'a ArgMatches<'a>> for ConfigWrapper {
    fn from(args: &'a ArgMatches<'a>) -> Self {
        info!("Creating config");
        let debug = args.is_present("debug");
        let verbose = args.is_present("verbose") || debug;
        let excluded_files = get_excluded(args);
        let excluded_files_raw = get_list(args, "exclude-files");

        let args_config = Config {
            name: String::new(),
            manifest: get_manifest(args),
            config: None,
            root: get_root(args),
            run_types: get_run_types(args),
            run_ignored: args.is_present("ignored"),
            ignore_tests: args.is_present("ignore-tests"),
            ignore_panics: args.is_present("ignore-panics"),
            force_clean: args.is_present("force-clean"),
            verbose,
            debug,
            count: args.is_present("count"),
            line_coverage: get_line_cov(args),
            branch_coverage: get_branch_cov(args),
            generate: get_outputs(args),
            output_directory: get_output_directory(args),
            coveralls: get_coveralls(args),
            ci_tool: get_ci(args),
            report_uri: get_report_uri(args),
            forward_signals: args.is_present("forward"),
            all_features: args.is_present("all-features"),
            no_default_features: args.is_present("no-default-features"),
            features: get_list(args, "features"),
            unstable_features: get_list(args, "Z"),
            all: args.is_present("all") | args.is_present("workspace"),
            packages: get_list(args, "packages"),
            exclude: get_list(args, "exclude"),
            excluded_files: RefCell::new(excluded_files.clone()),
            excluded_files_raw: excluded_files_raw.clone(),
            varargs: get_list(args, "args"),
            test_timeout: get_timeout(args),
            release: args.is_present("release"),
            no_run: args.is_present("no-run"),
            locked: args.is_present("locked"),
            frozen: args.is_present("frozen"),
            target_dir: get_target_dir(args),
            offline: args.is_present("offline"),
        };

        if args.is_present("config") {
            let mut path = PathBuf::from(args.value_of("config").unwrap());
            if path.is_relative() {
                path = env::current_dir()
                    .unwrap()
                    .join(path)
                    .canonicalize()
                    .unwrap();
            }
            let confs = Config::load_config_file(&path);
            if confs.is_err() {
                warn!("Failed to deserialize config file falling back to provided args");
                Self(vec![args_config])
            } else {
                let mut confs = confs.unwrap();
                for c in confs.iter_mut() {
                    c.config = Some(path.clone());
                    if debug {
                        c.debug = debug;
                        c.verbose = verbose;
                    } else if verbose {
                        c.verbose = verbose;
                    }
                    let mut conf_files = c.excluded_files.borrow_mut();
                    let mut compiled = regexes_from_excluded(&c.excluded_files_raw);
                    conf_files.append(&mut compiled);
                    if !excluded_files.is_empty() {
                        conf_files.extend_from_slice(&excluded_files);
                        c.excluded_files_raw.extend_from_slice(&excluded_files_raw);
                    }
                }

                if confs.is_empty() {
                    Self(vec![args_config])
                } else {
                    Self(confs)
                }
            }
        } else {
            Self(vec![args_config])
        }
    }
}

impl Config {
    pub fn load_config_file<P: AsRef<Path>>(file: P) -> std::io::Result<Vec<Self>> {
        let mut f = File::open(file)?;
        let mut buffer = Vec::new();
        f.read_to_end(&mut buffer)?;
        let mut map: HashMap<String, Self> = toml::from_slice(&buffer).map_err(|e| {
            error!("Invalid config file {}", e);
            Error::new(ErrorKind::InvalidData, format!("{}", e))
        })?;

        let mut result = Vec::new();
        for (name, mut conf) in map.iter_mut() {
            conf.name = name.to_string();
            result.push(conf.clone());
        }
        if result.is_empty() {
            Err(Error::new(ErrorKind::InvalidData, "No config tables"))
        } else {
            Ok(result)
        }
    }

    #[inline]
    pub fn is_coveralls(&self) -> bool {
        self.coveralls.is_some()
    }

    #[inline]
    pub fn exclude_path(&self, path: &Path) -> bool {
        if self.excluded_files.borrow().len() != self.excluded_files_raw.len() {
            let mut excluded_files = self.excluded_files.borrow_mut();
            let mut compiled = regexes_from_excluded(&self.excluded_files_raw);
            excluded_files.append(&mut compiled);
        }
        let project = self.strip_base_dir(path);

        self.excluded_files
            .borrow()
            .iter()
            .any(|x| x.is_match(project.to_str().unwrap_or("")))
    }

    ///
    /// returns the relative path from the base_dir
    /// uses root if set, else env::current_dir()
    ///
    #[inline]
    pub fn get_base_dir(&self) -> PathBuf {
        if let Some(root) = &self.root {
            if Path::new(root).is_absolute() {
                PathBuf::from(root)
            } else {
                let base_dir = env::current_dir().unwrap();
                base_dir.join(root).canonicalize().unwrap()
            }
        } else {
            env::current_dir().unwrap()
        }
    }

    /// returns the relative path from the base_dir
    ///
    #[inline]
    pub fn strip_base_dir(&self, path: &Path) -> PathBuf {
        path_relative_from(path, &self.get_base_dir()).unwrap_or_else(|| path.to_path_buf())
    }

    #[inline]
    pub fn is_default_output_dir(&self) -> bool {
        self.output_directory == env::current_dir().unwrap()
    }
}

/// Gets the relative path from one directory to another, if it exists.
/// Credit to brson from this commit from 2015
/// https://github.com/rust-lang/rust/pull/23283/files
///
fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
    use std::path::Component;

    if path.is_absolute() != base.is_absolute() {
        if path.is_absolute() {
            Some(path.to_path_buf())
        } else {
            None
        }
    } else {
        let mut ita = path.components();
        let mut itb = base.components();
        let mut comps = vec![];

        loop {
            match (ita.next(), itb.next()) {
                (None, None) => break,
                (Some(a), None) => {
                    comps.push(a);
                    comps.extend(ita.by_ref());
                    break;
                }
                (None, _) => comps.push(Component::ParentDir),
                (Some(a), Some(b)) if comps.is_empty() && a == b => (),
                (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
                (Some(_), Some(b)) if b == Component::ParentDir => return None,
                (Some(a), Some(_)) => {
                    comps.push(Component::ParentDir);
                    for _ in itb {
                        comps.push(Component::ParentDir);
                    }
                    comps.push(a);
                    comps.extend(ita.by_ref());
                    break;
                }
            }
        }
        Some(comps.iter().map(|c| c.as_os_str()).collect())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use clap::App;
    use std::collections::HashMap;

    #[test]
    fn exclude_paths() {
        let matches = App::new("tarpaulin")
            .args_from_usage("--exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'")
            .get_matches_from_safe(vec!["tarpaulin", "--exclude-files", "*module*"])
            .unwrap();
        let conf = Config::from(&matches);
        assert!(conf.exclude_path(Path::new("src/module/file.rs")));
        assert!(!conf.exclude_path(Path::new("src/mod.rs")));
        assert!(!conf.exclude_path(Path::new("unrelated.rs")));
        assert!(conf.exclude_path(Path::new("module.rs")));
    }

    #[test]
    fn no_exclusions() {
        let matches = App::new("tarpaulin")
            .args_from_usage("--exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'")
            .get_matches_from_safe(vec!["tarpaulin"])
            .unwrap();
        let conf = Config::from(&matches);
        assert!(!conf.exclude_path(Path::new("src/module/file.rs")));
        assert!(!conf.exclude_path(Path::new("src/mod.rs")));
        assert!(!conf.exclude_path(Path::new("unrelated.rs")));
        assert!(!conf.exclude_path(Path::new("module.rs")));
    }

    #[test]
    fn exclude_exact_file() {
        let matches = App::new("tarpaulin")
            .args_from_usage("--exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'")
            .get_matches_from_safe(vec!["tarpaulin", "--exclude-files", "*/lib.rs"])
            .unwrap();
        let conf = Config::from(&matches);
        assert!(conf.exclude_path(Path::new("src/lib.rs")));
        assert!(!conf.exclude_path(Path::new("src/mod.rs")));
        assert!(!conf.exclude_path(Path::new("src/notlib.rs")));
        assert!(!conf.exclude_path(Path::new("lib.rs")));
    }

    #[test]
    fn relative_path_test() {
        let path_a = Path::new("/this/should/form/a/rel/path/");
        let path_b = Path::new("/this/should/form/b/rel/path/");

        let rel_path = path_relative_from(path_b, path_a);
        assert!(rel_path.is_some());
        assert_eq!(
            rel_path.unwrap().to_str().unwrap(),
            "../../../b/rel/path",
            "Wrong relative path"
        );

        let path_a = Path::new("/this/should/not/form/a/rel/path/");
        let path_b = Path::new("./this/should/not/form/a/rel/path/");

        let rel_path = path_relative_from(path_b, path_a);
        assert_eq!(rel_path, None, "Did not expect relative path");

        let path_a = Path::new("./this/should/form/a/rel/path/");
        let path_b = Path::new("./this/should/form/b/rel/path/");

        let rel_path = path_relative_from(path_b, path_a);
        assert!(rel_path.is_some());
        assert_eq!(
            rel_path.unwrap().to_str().unwrap(),
            "../../../b/rel/path",
            "Wrong relative path"
        );
    }
}
<commit_msg>Update tests<commit_after>pub use self::types::*;

use self::parse::*;
use clap::ArgMatches;
use coveralls_api::CiService;
use log::{error, info, warn};
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{Error, ErrorKind, Read};
use std::path::{Path, PathBuf};
use std::time::Duration;

mod parse;
pub mod types;

pub struct ConfigWrapper(pub Vec<Config>);

/// Specifies the current configuration tarpaulin is using.
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct Config {
    pub name: String,
    /// Path to the projects cargo manifest
    pub manifest: PathBuf,
    /// Path to a tarpaulin.toml config file
    pub config: Option<PathBuf>,
    /// Path to the projects cargo manifest
    pub root: Option<String>,
    /// Flag to also run tests with the ignored attribute
    pub run_ignored: bool,
    /// Flag to ignore test functions in coverage statistics
    pub ignore_tests: bool,
    /// Ignore panic macros in code.
    pub ignore_panics: bool,
    /// Flag to add a clean step when preparing the target project
    pub force_clean: bool,
    /// Verbose flag for printing information to the user
    pub verbose: bool,
    /// Debug flag for printing internal debugging information to the user
    pub debug: bool,
    /// Flag to count hits in coverage
    pub count: bool,
    /// Flag specifying to run line coverage (default)
    pub line_coverage: bool,
    /// Flag specifying to run branch coverage
    pub branch_coverage: bool,
    /// Directory to write output files
    pub output_directory: PathBuf,
    /// Key relating to coveralls service or repo
    pub coveralls: Option<String>,
    /// Enum representing CI tool used.
    pub ci_tool: Option<CiService>,
    /// Only valid if coveralls option is set. If coveralls option is set,
    /// as well as report_uri, then the report will be sent to this endpoint
    /// instead.
    pub report_uri: Option<String>,
    /// Forward unexpected signals back to the tracee. Used for tests which
    /// rely on signals to work.
    pub forward_signals: bool,
    /// Include all available features in target build
    pub all_features: bool,
    /// Do not include default features in target build
    pub no_default_features: bool,
    /// Build all packages in the workspace
    pub all: bool,
    /// Duration to wait before a timeout occurs
    pub test_timeout: Duration,
    /// Build in release mode
    pub release: bool,
    /// Build the tests only don't run coverage
    pub no_run: bool,
    /// Don't update `Cargo.lock`.
    pub locked: bool,
    /// Don't update `Cargo.lock` or any caches.
    pub frozen: bool,
    /// Directory for generated artifacts
    pub target_dir: Option<PathBuf>,
    /// Run tarpaulin on project without accessing the network
    pub offline: bool,
    /// Types of tests for tarpaulin to collect coverage on
    pub run_types: Vec<RunType>,
    /// Packages to include when building the target project
    pub packages: Vec<String>,
    /// Packages to exclude from testing
    pub exclude: Vec<String>,
    /// Files to exclude from testing in their compiled form
    #[serde(skip_deserializing, skip_serializing)]
    excluded_files: RefCell<Vec<Regex>>,
    /// Files to exclude from testing in uncompiled form (for serde)
    excluded_files_raw: Vec<String>,
    /// Varargs to be forwarded to the test executables.
    pub varargs: Vec<String>,
    /// Features to include in the target project build
    pub features: Vec<String>,
    /// Unstable cargo features to use
    pub unstable_features: Vec<String>,
    /// Output files to generate
    pub generate: Vec<OutputFile>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            name: String::new(),
            run_types: vec![RunType::Tests],
            manifest: default_manifest(),
            config: None,
            root: Default::default(),
            run_ignored: false,
            ignore_tests: false,
            ignore_panics: false,
            force_clean: false,
            verbose: false,
            debug: false,
            count: false,
            line_coverage: true,
            branch_coverage: false,
            generate: vec![],
            output_directory: Default::default(),
            coveralls: None,
            ci_tool: None,
            report_uri: None,
            forward_signals: false,
            no_default_features: false,
            features: vec![],
            unstable_features: vec![],
            all: false,
            packages: vec![],
            exclude: vec![],
            excluded_files: RefCell::new(vec![]),
            excluded_files_raw: vec![],
            varargs: vec![],
            test_timeout: Duration::from_secs(60),
            release: false,
            all_features: false,
            no_run: false,
            locked: false,
            frozen: false,
            target_dir: None,
            offline: false,
        }
    }
}

impl<'a> From<&'a ArgMatches<'a>> for ConfigWrapper {
    fn from(args: &'a ArgMatches<'a>) -> Self {
        info!("Creating config");
        let debug = args.is_present("debug");
        let verbose = args.is_present("verbose") || debug;
        let excluded_files = get_excluded(args);
        let excluded_files_raw = get_list(args, "exclude-files");

        let args_config = Config {
            name: String::new(),
            manifest: get_manifest(args),
            config: None,
            root: get_root(args),
            run_types: get_run_types(args),
            run_ignored: args.is_present("ignored"),
            ignore_tests: args.is_present("ignore-tests"),
            ignore_panics: args.is_present("ignore-panics"),
            force_clean: args.is_present("force-clean"),
            verbose,
            debug,
            count: args.is_present("count"),
            line_coverage: get_line_cov(args),
            branch_coverage: get_branch_cov(args),
            generate: get_outputs(args),
            output_directory: get_output_directory(args),
            coveralls: get_coveralls(args),
            ci_tool: get_ci(args),
            report_uri: get_report_uri(args),
            forward_signals: args.is_present("forward"),
            all_features: args.is_present("all-features"),
            no_default_features: args.is_present("no-default-features"),
            features: get_list(args, "features"),
            unstable_features: get_list(args, "Z"),
            all: args.is_present("all") | args.is_present("workspace"),
            packages: get_list(args, "packages"),
            exclude: get_list(args, "exclude"),
            excluded_files: RefCell::new(excluded_files.clone()),
            excluded_files_raw: excluded_files_raw.clone(),
            varargs: get_list(args, "args"),
            test_timeout: get_timeout(args),
            release: args.is_present("release"),
            no_run: args.is_present("no-run"),
            locked: args.is_present("locked"),
            frozen: args.is_present("frozen"),
            target_dir: get_target_dir(args),
            offline: args.is_present("offline"),
        };

        if args.is_present("config") {
            let mut path = PathBuf::from(args.value_of("config").unwrap());
            if path.is_relative() {
                path = env::current_dir()
                    .unwrap()
                    .join(path)
                    .canonicalize()
                    .unwrap();
            }
            let confs = Config::load_config_file(&path);
            if confs.is_err() {
                warn!("Failed to deserialize config file falling back to provided args");
                Self(vec![args_config])
            } else {
                let mut confs = confs.unwrap();
                for c in confs.iter_mut() {
                    c.config = Some(path.clone());
                    if debug {
                        c.debug = debug;
                        c.verbose = verbose;
                    } else if verbose {
                        c.verbose = verbose;
                    }
                    let mut conf_files = c.excluded_files.borrow_mut();
                    let mut compiled = regexes_from_excluded(&c.excluded_files_raw);
                    conf_files.append(&mut compiled);
                    if !excluded_files.is_empty() {
                        conf_files.extend_from_slice(&excluded_files);
                        c.excluded_files_raw.extend_from_slice(&excluded_files_raw);
                    }
                }

                if confs.is_empty() {
                    Self(vec![args_config])
                } else {
                    Self(confs)
                }
            }
        } else {
            Self(vec![args_config])
        }
    }
}

impl Config {
    pub fn load_config_file<P: AsRef<Path>>(file: P) -> std::io::Result<Vec<Self>> {
        let mut f = File::open(file)?;
        let mut buffer = Vec::new();
        f.read_to_end(&mut buffer)?;
        let mut map: HashMap<String, Self> = toml::from_slice(&buffer).map_err(|e| {
            error!("Invalid config file {}", e);
            Error::new(ErrorKind::InvalidData, format!("{}", e))
        })?;

        let mut result = Vec::new();
        for (name, mut conf) in map.iter_mut() {
            conf.name = name.to_string();
            result.push(conf.clone());
        }
        if result.is_empty() {
            Err(Error::new(ErrorKind::InvalidData, "No config tables"))
        } else {
            Ok(result)
        }
    }

    #[inline]
    pub fn is_coveralls(&self) -> bool {
        self.coveralls.is_some()
    }

    #[inline]
    pub fn exclude_path(&self, path: &Path) -> bool {
        if self.excluded_files.borrow().len() != self.excluded_files_raw.len() {
            let mut excluded_files = self.excluded_files.borrow_mut();
            let mut compiled = regexes_from_excluded(&self.excluded_files_raw);
            excluded_files.append(&mut compiled);
        }
        let project = self.strip_base_dir(path);

        self.excluded_files
            .borrow()
            .iter()
            .any(|x| x.is_match(project.to_str().unwrap_or("")))
    }

    ///
    /// returns the relative path from the base_dir
    /// uses root if set, else env::current_dir()
    ///
    #[inline]
    pub fn get_base_dir(&self) -> PathBuf {
        if let Some(root) = &self.root {
            if Path::new(root).is_absolute() {
                PathBuf::from(root)
            } else {
                let base_dir = env::current_dir().unwrap();
                base_dir.join(root).canonicalize().unwrap()
            }
        } else {
            env::current_dir().unwrap()
        }
    }

    /// returns the relative path from the base_dir
    ///
    #[inline]
    pub fn strip_base_dir(&self, path: &Path) -> PathBuf {
        path_relative_from(path, &self.get_base_dir()).unwrap_or_else(|| path.to_path_buf())
    }

    #[inline]
    pub fn is_default_output_dir(&self) -> bool {
        self.output_directory == env::current_dir().unwrap()
    }
}

/// Gets the relative path from one directory to another, if it exists.
/// Credit to brson from this commit from 2015
/// https://github.com/rust-lang/rust/pull/23283/files
///
fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
    use std::path::Component;

    if path.is_absolute() != base.is_absolute() {
        if path.is_absolute() {
            Some(path.to_path_buf())
        } else {
            None
        }
    } else {
        let mut ita = path.components();
        let mut itb = base.components();
        let mut comps = vec![];

        loop {
            match (ita.next(), itb.next()) {
                (None, None) => break,
                (Some(a), None) => {
                    comps.push(a);
                    comps.extend(ita.by_ref());
                    break;
                }
                (None, _) => comps.push(Component::ParentDir),
                (Some(a), Some(b)) if comps.is_empty() && a == b => (),
                (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
                (Some(_), Some(b)) if b == Component::ParentDir => return None,
                (Some(a), Some(_)) => {
                    comps.push(Component::ParentDir);
                    for _ in itb {
                        comps.push(Component::ParentDir);
                    }
                    comps.push(a);
                    comps.extend(ita.by_ref());
                    break;
                }
            }
        }
        Some(comps.iter().map(|c| c.as_os_str()).collect())
    }
}

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

    #[test]
    fn exclude_paths() {
        let matches = App::new("tarpaulin")
            .args_from_usage("--exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'")
            .get_matches_from_safe(vec!["tarpaulin", "--exclude-files", "*module*"])
            .unwrap();
        let conf = ConfigWrapper::from(&matches).0;
        assert_eq!(conf.len(), 1);
        assert!(conf[0].exclude_path(Path::new("src/module/file.rs")));
        assert!(!conf[0].exclude_path(Path::new("src/mod.rs")));
        assert!(!conf[0].exclude_path(Path::new("unrelated.rs")));
        assert!(conf[0].exclude_path(Path::new("module.rs")));
    }

    #[test]
    fn no_exclusions() {
        let matches = App::new("tarpaulin")
            .args_from_usage("--exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'")
            .get_matches_from_safe(vec!["tarpaulin"])
            .unwrap();
        let conf = ConfigWrapper::from(&matches).0;
        assert_eq!(conf.len(), 1);
        assert!(!conf[0].exclude_path(Path::new("src/module/file.rs")));
        assert!(!conf[0].exclude_path(Path::new("src/mod.rs")));
        assert!(!conf[0].exclude_path(Path::new("unrelated.rs")));
        assert!(!conf[0].exclude_path(Path::new("module.rs")));
    }

    #[test]
    fn exclude_exact_file() {
        let matches = App::new("tarpaulin")
            .args_from_usage("--exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'")
            .get_matches_from_safe(vec!["tarpaulin", "--exclude-files", "*/lib.rs"])
            .unwrap();
        let conf = ConfigWrapper::from(&matches).0;
        assert_eq!(conf.len(), 1);
        assert!(conf[0].exclude_path(Path::new("src/lib.rs")));
        assert!(!conf[0].exclude_path(Path::new("src/mod.rs")));
        assert!(!conf[0].exclude_path(Path::new("src/notlib.rs")));
        assert!(!conf[0].exclude_path(Path::new("lib.rs")));
    }

    #[test]
    fn relative_path_test() {
        let path_a = Path::new("/this/should/form/a/rel/path/");
        let path_b = Path::new("/this/should/form/b/rel/path/");

        let rel_path = path_relative_from(path_b, path_a);
        assert!(rel_path.is_some());
        assert_eq!(
            rel_path.unwrap().to_str().unwrap(),
            "../../../b/rel/path",
            "Wrong relative path"
        );

        let path_a = Path::new("/this/should/not/form/a/rel/path/");
        let path_b = Path::new("./this/should/not/form/a/rel/path/");

        let rel_path = path_relative_from(path_b, path_a);
        assert_eq!(rel_path, None, "Did not expect relative path");

        let path_a = Path::new("./this/should/form/a/rel/path/");
        let path_b = Path::new("./this/should/form/b/rel/path/");

        let rel_path = path_relative_from(path_b, path_a);
        assert!(rel_path.is_some());
        assert_eq!(
            rel_path.unwrap().to_str().unwrap(),
            "../../../b/rel/path",
            "Wrong relative path"
        );
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::net::TcpStream;
use std::fmt;

use error::{Error, Result};

pub struct KafkaConnection {
    host: String,
    timeout: i32,
    stream: TcpStream
}

impl fmt::Debug for KafkaConnection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "KafkaConnection to {}", self.host)
    }
}

impl KafkaConnection {

    pub fn send(&mut self, msg: &Vec<u8>) -> Result<usize> {
        self.stream.write(&msg[..]).map_err(From::from)
    }

    pub fn read_exact(&mut self, size: u64) -> Result<Vec<u8>> {
        let mut buffer: Vec<u8> = Vec::with_capacity(size as usize);
        let mut s = (&self.stream).take(size);
        let bytes_read = try!(s.read_to_end(&mut buffer));
        if bytes_read != size as usize {
            Err(Error::UnexpectedEOF)
        } else {
            Ok(buffer)
        }
    }

    pub fn new(host: &str, timeout: i32) -> Result<KafkaConnection> {
        let stream = try!(TcpStream::connect(host));
        Ok(KafkaConnection{host: host.to_owned(), timeout: timeout, stream: stream})
    }
}
<commit_msg>#! Set read/write timeout on connection<commit_after>use std::fmt;
use std::io::{Read,Write};
use std::net::TcpStream;
use std::time::Duration;

use error::{Error, Result};

pub struct KafkaConnection {
    host: String,
    stream: TcpStream
}

impl fmt::Debug for KafkaConnection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "KafkaConnection to {}", self.host)
    }
}

impl KafkaConnection {

    pub fn send(&mut self, msg: &Vec<u8>) -> Result<usize> {
        self.stream.write(&msg[..]).map_err(From::from)
    }

    pub fn read_exact(&mut self, size: u64) -> Result<Vec<u8>> {
        let mut buffer: Vec<u8> = Vec::with_capacity(size as usize);
        let mut s = (&self.stream).take(size);
        let bytes_read = try!(s.read_to_end(&mut buffer));
        if bytes_read != size as usize {
            Err(Error::UnexpectedEOF)
        } else {
            Ok(buffer)
        }
    }

    pub fn new(host: &str, timeout_secs: i32) -> Result<KafkaConnection> {
        let stream = try!(TcpStream::connect(host));
        if timeout_secs > 0 {
            let t = Some(Duration::from_secs(timeout_secs as u64));
            stream.set_read_timeout(t).expect("Set connection read-timeout");
            stream.set_write_timeout(t).expect("Set connection write-timeout");
        }
        Ok(KafkaConnection{host: host.to_owned(), stream: stream})
    }
}
<|endoftext|>


<commit_before>use Result;
use Error;
use std::path::{PathBuf, Path};
use schema::Schema;
use std::io::Write;
use std::sync::{Arc, RwLock};
use std::fmt;
use rustc_serialize::json;
use core::SegmentId;
use directory::{Directory, MmapDirectory, RAMDirectory};
use indexer::IndexWriter;
use core::searcher::Searcher;
use std::convert::From;
use num_cpus;
use std::collections::HashSet;
use super::segment::Segment;
use core::SegmentReader;

#[derive(Clone,Debug,RustcDecodable,RustcEncodable)]
pub struct IndexMeta {
    segments: Vec<SegmentId>,
    schema: Schema,
    docstamp: u64,
}

impl IndexMeta {
    fn with_schema(schema: Schema) -> IndexMeta {
        IndexMeta {
            segments: Vec::new(),
            schema: schema,
            docstamp: 0u64,
        }
    }
}

impl fmt::Debug for Index {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!(f, "Index({:?})", self.directory)
   }
}

pub struct Index {
    metas: Arc<RwLock<IndexMeta>>,
    directory: Box<Directory>,
    schema: Schema,
}

impl Clone for Index {
    fn clone(&self,) -> Index {
        Index {
            metas: self.metas.clone(),
            directory: self.directory.box_clone(),
            schema: self.schema.clone(),
        }
    }
}

lazy_static! {
    static ref META_FILEPATH: PathBuf = PathBuf::from("meta.json");
}

fn load_metas(directory: &Directory) -> Result<IndexMeta> {
    let meta_file = try!(directory.open_read(&META_FILEPATH));
    let meta_content = String::from_utf8_lossy(meta_file.as_slice());
    let loaded_meta = try!(
        json::decode(&meta_content)
            .map_err(|e| Error::CorruptedFile(META_FILEPATH.clone(), Box::new(e)))
    );
    Ok(loaded_meta)
}

impl Index {

    pub fn create_in_ram(schema: Schema) -> Index {
        let directory = Box::new(RAMDirectory::create());
        Index::from_directory(directory, schema)
    }

    pub fn create(directory_path: &Path, schema: Schema) -> Result<Index> {
        let directory = Box::new(try!(MmapDirectory::open(directory_path)));
        Ok(Index::from_directory(directory, schema))
    }

    pub fn create_from_tempdir(schema: Schema) -> Result<Index> {
        let directory = Box::new(try!(MmapDirectory::create_from_tempdir()));
        Ok(Index::from_directory(directory, schema))
    }

    pub fn open(directory_path: &Path) -> Result<Index> {
        let directory = try!(MmapDirectory::open(directory_path));
        let metas = try!(load_metas(&directory)); //< TODO does the directory already exists?
        let schema = metas.schema.clone();
        let locked_metas = Arc::new(RwLock::new(metas));
        Ok(Index {
            directory: Box::new(directory),
            metas: locked_metas,
            schema: schema,
        })
    }

    pub fn docstamp(&self,) -> Result<u64> {
        self.metas
            .read()
            .map(|metas| metas.docstamp)
            .map_err(From::from)
    }

    /// Creates a multithreaded writer.
    /// Each writer produces an independant segment.
    pub fn writer_with_num_threads(&self, num_threads: usize) -> Result<IndexWriter> {
        IndexWriter::open(self, num_threads)
    }

    /// Creates a multithreaded writer
    /// It just calls `writer_with_num_threads` with the number of core as `num_threads`
    pub fn writer(&self,) -> Result<IndexWriter> {
        self.writer_with_num_threads(num_cpus::get())
    }

    pub fn from_directory(directory: Box<Directory>, schema: Schema) -> Index {
        Index {
            metas: Arc::new(RwLock::new(IndexMeta::with_schema(schema.clone()))),
            directory: directory,
            schema: schema,
        }
    }

    pub fn schema(&self,) -> Schema {
        self.schema.clone()
    }

    /// Marks the segment as published.
    // TODO find a rusty way to hide that, while keeping
    // it visible for IndexWriters.
    pub fn publish_segments(&mut self,
            segment_ids: &[SegmentId],
            docstamp: u64) -> Result<()> {
        {
            let mut meta_write = try!(self.metas.write());
            meta_write.segments.extend(segment_ids);
            meta_write.docstamp = docstamp;
        }
        try!(self.save_metas());
        Ok(())
    }

    pub fn publish_merge_segment(&mut self, segment_merged_ids: HashSet<SegmentId>, merged_segment_id: SegmentId) -> Result<()> {
        {
            let mut meta_write = try!(self.metas.write());
            let mut new_segment_ids: Vec<SegmentId> = meta_write
                .segments
                .iter()
                .filter(|&segment_id| !segment_merged_ids.contains(segment_id))
                .cloned()
                .collect();
            new_segment_ids.push(merged_segment_id);
            meta_write.segments = new_segment_ids;
        }
        try!(self.save_metas());
        Ok(())
    }

    pub fn segments(&self,) -> Vec<Segment> {
        self.segment_ids()
            .into_iter()
            .map(|segment_id| self.segment(segment_id))
            .collect()
    }

    pub fn segment(&self, segment_id: SegmentId) -> Segment {
        Segment::new(self.clone(), segment_id)
    }

    pub fn directory(&self,) -> &Directory {
        &*self.directory
    }

    pub fn directory_mut(&mut self,) -> &mut Directory {
        &mut *self.directory
    }

    fn segment_ids(&self,) -> Vec<SegmentId> {
        self.metas
            .read()
            .unwrap()
            .segments
            .iter()
            .cloned()
            .collect()
    }

    pub fn new_segment(&self,) -> Segment {
        self.segment(SegmentId::new())
    }

    pub fn save_metas(&mut self,) -> Result<()> {
        let mut w = Vec::new();
        {
            let metas_lock = self.metas.read().unwrap();
            try!(write!(&mut w, "{}\n", json::as_pretty_json(&*metas_lock)));
        };
        self.directory
            .atomic_write(&META_FILEPATH, &w[..])
            .map_err(From::from)
    }

    pub fn searcher(&self,) -> Result<Searcher> {
        let segment_readers: Vec<SegmentReader> = try!(
            self.segments()
                .into_iter()
                .map(SegmentReader::open)
                .collect()
        );
        Ok(Searcher::from_readers(segment_readers))
    }
}

<commit_msg>small refactoring<commit_after>use Result;
use Error;
use std::path::{PathBuf, Path};
use schema::Schema;
use std::io::Write;
use std::sync::{Arc, RwLock};
use std::fmt;
use rustc_serialize::json;
use core::SegmentId;
use directory::{Directory, MmapDirectory, RAMDirectory};
use indexer::IndexWriter;
use core::searcher::Searcher;
use std::convert::From;
use num_cpus;
use std::collections::HashSet;
use super::segment::Segment;
use core::SegmentReader;

#[derive(Clone,Debug,RustcDecodable,RustcEncodable)]
pub struct IndexMeta {
    segments: Vec<SegmentId>,
    schema: Schema,
    docstamp: u64,
}

impl IndexMeta {
    fn with_schema(schema: Schema) -> IndexMeta {
        IndexMeta {
            segments: Vec::new(),
            schema: schema,
            docstamp: 0u64,
        }
    }
}

impl fmt::Debug for Index {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!(f, "Index({:?})", self.directory)
   }
}

pub struct Index {
    metas: Arc<RwLock<IndexMeta>>,
    directory: Box<Directory>,
    schema: Schema,
}

impl Clone for Index {
    fn clone(&self,) -> Index {
        Index {
            metas: self.metas.clone(),
            directory: self.directory.box_clone(),
            schema: self.schema.clone(),
        }
    }
}

lazy_static! {
    static ref META_FILEPATH: PathBuf = PathBuf::from("meta.json");
}

fn load_metas(directory: &Directory) -> Result<IndexMeta> {
    let meta_file = try!(directory.open_read(&META_FILEPATH));
    let meta_content = String::from_utf8_lossy(meta_file.as_slice());
    let loaded_meta = try!(
        json::decode(&meta_content)
            .map_err(|e| Error::CorruptedFile(META_FILEPATH.clone(), Box::new(e)))
    );
    Ok(loaded_meta)
}

impl Index {

    pub fn create_in_ram(schema: Schema) -> Index {
        let directory = Box::new(RAMDirectory::create());
        Index::from_directory(directory, schema).unwrap()
    }

    pub fn create(directory_path: &Path, schema: Schema) -> Result<Index> {
        let directory = Box::new(try!(MmapDirectory::open(directory_path)));
        Index::from_directory(directory, schema)
    }

    pub fn create_from_tempdir(schema: Schema) -> Result<Index> {
        let directory = Box::new(try!(MmapDirectory::create_from_tempdir()));
        Index::from_directory(directory, schema)
    }

    fn create_from_metas(directory: Box<Directory>, metas: IndexMeta) -> Result<Index> {
        let schema = metas.schema.clone();
        Ok(Index {
            directory: directory,
            metas: Arc::new(RwLock::new(metas)),
            schema: schema,
        })
    }

    pub fn from_directory(directory: Box<Directory>, schema: Schema) -> Result<Index> {
        let mut index = try!(Index::create_from_metas(directory, IndexMeta::with_schema(schema)));
        try!(index.save_metas());
        Ok(index)
    }

    pub fn open(directory_path: &Path) -> Result<Index> {
        let directory = try!(MmapDirectory::open(directory_path));
        let metas = try!(load_metas(&directory)); //< TODO does the directory already exists?
        Index::create_from_metas(directory.box_clone(), metas)
    }

    pub fn docstamp(&self,) -> Result<u64> {
        self.metas
            .read()
            .map(|metas| metas.docstamp)
            .map_err(From::from)
    }

    /// Creates a multithreaded writer.
    /// Each writer produces an independant segment.
    pub fn writer_with_num_threads(&self, num_threads: usize) -> Result<IndexWriter> {
        IndexWriter::open(self, num_threads)
    }

    /// Creates a multithreaded writer
    /// It just calls `writer_with_num_threads` with the number of core as `num_threads`
    pub fn writer(&self,) -> Result<IndexWriter> {
        self.writer_with_num_threads(num_cpus::get())
    }

    pub fn schema(&self,) -> Schema {
        self.schema.clone()
    }

    /// Marks the segment as published.
    // TODO find a rusty way to hide that, while keeping
    // it visible for IndexWriters.
    pub fn publish_segments(&mut self,
            segment_ids: &[SegmentId],
            docstamp: u64) -> Result<()> {
        {
            let mut meta_write = try!(self.metas.write());
            meta_write.segments.extend(segment_ids);
            meta_write.docstamp = docstamp;
        }
        try!(self.save_metas());
        Ok(())
    }

    pub fn publish_merge_segment(&mut self, segment_merged_ids: HashSet<SegmentId>, merged_segment_id: SegmentId) -> Result<()> {
        {
            let mut meta_write = try!(self.metas.write());
            let mut new_segment_ids: Vec<SegmentId> = meta_write
                .segments
                .iter()
                .filter(|&segment_id| !segment_merged_ids.contains(segment_id))
                .cloned()
                .collect();
            new_segment_ids.push(merged_segment_id);
            meta_write.segments = new_segment_ids;
        }
        try!(self.save_metas());
        Ok(())
    }

    pub fn segments(&self,) -> Vec<Segment> {
        self.segment_ids()
            .into_iter()
            .map(|segment_id| self.segment(segment_id))
            .collect()
    }

    pub fn segment(&self, segment_id: SegmentId) -> Segment {
        Segment::new(self.clone(), segment_id)
    }

    pub fn directory(&self,) -> &Directory {
        &*self.directory
    }

    pub fn directory_mut(&mut self,) -> &mut Directory {
        &mut *self.directory
    }

    fn segment_ids(&self,) -> Vec<SegmentId> {
        self.metas
            .read()
            .unwrap()
            .segments
            .iter()
            .cloned()
            .collect()
    }

    pub fn new_segment(&self,) -> Segment {
        self.segment(SegmentId::new())
    }

    pub fn save_metas(&mut self,) -> Result<()> {
        let mut w = Vec::new();
        {
            let metas_lock = self.metas.read().unwrap();
            try!(write!(&mut w, "{}\n", json::as_pretty_json(&*metas_lock)));
        };
        self.directory
            .atomic_write(&META_FILEPATH, &w[..])
            .map_err(From::from)
    }

    pub fn searcher(&self,) -> Result<Searcher> {
        let segment_readers: Vec<SegmentReader> = try!(
            self.segments()
                .into_iter()
                .map(SegmentReader::open)
                .collect()
        );
        Ok(Searcher::from_readers(segment_readers))
    }
}

<|endoftext|>


<commit_before>use serde::{ Serialize, Serializer };
use serde;

mod content;
pub use self::content::*;

mod traits;
pub use self::traits::*;

use super::common_types::*;

#[derive(Deserialize,Debug,PartialEq)]
pub struct Submessage {
    pub id: SubmessageId,
    // TODO: single byte is multi-purpose, switch to bitflag
    // add multicast flag
    pub endianness: Endianness,

    pub buf: ArcBuffer,
}

#[derive(Deserialize,Debug,PartialEq)]
pub struct SubmessageV2 {
    pub variant: SubmessageVariant
}

/// 8.3.4.1 Rules Followed by the Message Receiver
#[derive(Debug,PartialEq)]
pub enum SubmessageVariant {
    // Interpreter Submessages
    InfoDestination( GuidPrefix ),
    // TODO: not positive the on-wire format of a Locator_t*. Not length-prefixed?
    InfoReply{ unicast_locator_list: LocatorList /* , multicast_locator_list: Option<LocatorList> TODO: relies on presence of multicast flag above */ },
    InfoSource{ protocol_version: ProtocolVersion, vendor_id: VendorId, guid_prefix: GuidPrefix},
    InfoTimestamp(Timestamp),

    // Entity Submessages
    AckNack { reader_id: EntityId, writer_id: EntityId, reader_sn_state: SequenceNumberSet, count: Count  },
    Data { reader_id: EntityId, writer_id: EntityId, writer_sn: SequenceNumber/*, inline_qos: Option<InlineQOS> */, serialized_payload: ArcBuffer  },
    // TODO: Data frag will require a 'buffer farm' concept so we can process multiple messages then form a single cache_change
    DataFrag { reader_id: EntityId, writer_id: EntityId, writer_sn: SequenceNumber, fragment_start_num: FragmentNumber, fragments_in_submessage: u16, data_size: u32, fragment_size: u16, /*, inline_qos: Option<InlineQOS>, */ serialized_payload: ArcBuffer },
    Gap { reader_id: EntityId, writer_id: EntityId, gap_start: SequenceNumber, gap_list: SequenceNumberSet },
    HeartBeat { reader_id: EntityId, writer_id: EntityId, first_sn: SequenceNumber, last_sn: SequenceNumber, count: Count },
    HeartbeatFrag { reader_id: EntityId, writer_id: EntityId, writer_sn: SequenceNumber, last_fragment_number: FragmentNumber, count: Count },
    NackFrag { reader_id: EntityId, writer_id: EntityId, writer_sn: SequenceNumber, fragment_number_state: FragmentNumberSet, count: Count },
    Pad
}

impl serde::Deserialize for SubmessageVariant {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: serde::Deserializer {
        let kind : SubmessageId = try!(serde::Deserialize::deserialize(deserializer));
        let _ : u8 = try!(serde::Deserialize::deserialize(deserializer));
        // len of message. TODO: use to confirm the proper number of bytes are read
        let _ : u32 = try!(serde::Deserialize::deserialize(deserializer));

        match kind {
            SubmessageId::INFO_TS => {
                // Wow, such terse
                Ok(SubmessageVariant::InfoTimestamp(try!(serde::Deserialize::deserialize(deserializer))))
            },
            SubmessageId::INFO_SRC => {
                Ok(SubmessageVariant::InfoSource{
                    protocol_version: try!(serde::Deserialize::deserialize(deserializer)),
                    vendor_id: try!(serde::Deserialize::deserialize(deserializer)),
                    guid_prefix: try!(serde::Deserialize::deserialize(deserializer))
                })
            },
            SubmessageId::INFO_REPLY => {
                Ok(SubmessageVariant::InfoReply{
                    unicast_locator_list: try!(serde::Deserialize::deserialize(deserializer))
                })
            },
            SubmessageId::INFO_DST => {
                Ok(SubmessageVariant::InfoDestination(try!(serde::Deserialize::deserialize(deserializer))))
            },
            SubmessageId::INFO_REPLY_IP4 => {
                Err(serde::Error::custom("we don't do ipv4 specialization yet"))
//                0x0f
            },

            SubmessageId::ACKNACK => {
                Ok(SubmessageVariant::AckNack {
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    reader_sn_state: try!(serde::Deserialize::deserialize(deserializer)),
                    count: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::DATA => {
                Ok(SubmessageVariant::Data {
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    serialized_payload: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::DATA_FRAG => {
                Ok(SubmessageVariant::DataFrag {
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_sn: try!(serde::Deserialize::deserialize(deserializer)),

                    fragment_start_num: try!(serde::Deserialize::deserialize(deserializer)),
                    fragments_in_submessage: try!(serde::Deserialize::deserialize(deserializer)),
                    data_size: try!(serde::Deserialize::deserialize(deserializer)),
                    fragment_size: try!(serde::Deserialize::deserialize(deserializer)),

                    serialized_payload: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::HEARTBEAT => {
                Ok(SubmessageVariant::HeartBeat{
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    first_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    last_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    count: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::HEARTBEAT_FRAG => {
                Ok(SubmessageVariant::HeartbeatFrag {
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    last_fragment_number: try!(serde::Deserialize::deserialize(deserializer)),
                    count: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::GAP => {
                Ok(SubmessageVariant::Gap{
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    gap_start: try!(serde::Deserialize::deserialize(deserializer)),
                    gap_list: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },

            SubmessageId::NACK_FRAG => {
                Ok(SubmessageVariant::NackFrag{
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    fragment_number_state: try!(serde::Deserialize::deserialize(deserializer)),
                    count: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::PAD => {
                Ok(SubmessageVariant::Pad)
            }
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Debug,PartialEq)]
pub enum SubmessageId {
    PAD,
    ACKNACK,
    HEARTBEAT,
    GAP,
    INFO_TS,
    INFO_SRC,
    INFO_REPLY_IP4,
    INFO_DST,
    INFO_REPLY,
    NACK_FRAG,
    HEARTBEAT_FRAG,
    DATA,
    DATA_FRAG,
}

impl Serialize for SubmessageId {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let val = match *self {
            SubmessageId::PAD => 0x01, /* Pad */
            SubmessageId::ACKNACK => 0x06, /* AckNack */
            SubmessageId::HEARTBEAT => 0x07, /* Heartbeat */
            SubmessageId::GAP => 0x08, /* Gap */
            SubmessageId::INFO_TS => 0x09, /* InfoTimestamp */
            SubmessageId::INFO_SRC => 0x0c, /* InfoSource */
            SubmessageId::INFO_REPLY_IP4 => 0x0d, /* InfoReplyIp4 */
            SubmessageId::INFO_DST => 0x0e, /* InfoDestination */
            SubmessageId::INFO_REPLY => 0x0f, /* InfoReply */
            SubmessageId::NACK_FRAG => 0x12, /* NackFrag */
            SubmessageId::HEARTBEAT_FRAG => 0x13, /* HeartbeatFrag */
            SubmessageId::DATA => 0x15, /* Data */
            SubmessageId::DATA_FRAG => 0x16, /* DataFrag */
        };
        serializer.serialize_u8(val)
    }
}

impl serde::Deserialize for SubmessageId {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: serde::Deserializer {
        let byte : u8 = try!(serde::Deserialize::deserialize(deserializer));
        match byte {
            0x01 => Ok(SubmessageId::PAD), /* Pad */
            0x06 => Ok(SubmessageId::ACKNACK), /* AckNack */
            0x07 => Ok(SubmessageId::HEARTBEAT), /* Heartbeat */
            0x08 => Ok(SubmessageId::GAP), /* Gap */
            0x09 => Ok(SubmessageId::INFO_TS), /* InfoTimestamp */
            0x0c => Ok(SubmessageId::INFO_SRC), /* InfoSource */
            0x0d => Ok(SubmessageId::INFO_REPLY_IP4), /* InfoReplyIp4 */
            0x0e => Ok(SubmessageId::INFO_DST), /* InfoDestination */
            0x0f => Ok(SubmessageId::INFO_REPLY), /* InfoReply */
            0x12 => Ok(SubmessageId::NACK_FRAG), /* NackFrag */
            0x13 => Ok(SubmessageId::HEARTBEAT_FRAG), /* HeartbeatFrag */
            0x15 => Ok(SubmessageId::DATA), /* Data */
            0x16 => Ok(SubmessageId::DATA_FRAG), /* DataFrag */
            _ => {
                Err(serde::Error::custom(format!("unknown type {:?}", byte)))
//                Err(CdrDeserializerError{ thing: format!("unknown type {:?}", byte) })
            },
        }
    }
}

bitflags! {
    pub flags SubmessageFlags: u8 {
        const LITTLE_ENDIAN = 0x01,
        const ACK_NACK_FINAL_FLAG = 0x02,

        const DATA_INLINE_QOS = 0x02,
        const DATA_DATA = 0x04,
        const DATA_KEY = 0x08,
        const DATA_FRAG_INLINE_QOS = 0x02,
        // eh, will add more as-needed
    }
}

impl Serialize for Submessage {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        // Write the submessage id
        try!(self.id.serialize(serializer));

        // Write the submessage flags (aka, the endianness)
        let flags : u8 = match self.endianness {
            Endianness::Little => 1,
            Endianness::Big => 0
        };
        try!(serializer.serialize_u8(flags));

        try!(serializer.serialize_u32(self.buf.len() as u32));
        serializer.serialize_bytes(self.buf.buf())
    }
}<commit_msg>reformatting<commit_after>use serde::{ Serialize, Serializer };
use serde;

mod content;
pub use self::content::*;

mod traits;
pub use self::traits::*;

use super::common_types::*;

#[derive(Deserialize,Debug,PartialEq)]
pub struct Submessage {
    pub id: SubmessageId,
    // TODO: single byte is multi-purpose, switch to bitflag
    // add multicast flag
    pub endianness: Endianness,

    pub buf: ArcBuffer,
}

#[derive(Deserialize,Debug,PartialEq)]
pub struct SubmessageV2 {
    pub variant: SubmessageVariant
}

/// 8.3.4.1 Rules Followed by the Message Receiver
#[derive(Debug,PartialEq)]
pub enum SubmessageVariant {
    // Interpreter Submessages
    InfoDestination( GuidPrefix ),
    // TODO: not positive the on-wire format of a Locator_t*. Not length-prefixed?
    InfoReply{ unicast_locator_list: LocatorList /* , multicast_locator_list: Option<LocatorList> TODO: relies on presence of multicast flag above */ },
    InfoSource{ protocol_version: ProtocolVersion, vendor_id: VendorId, guid_prefix: GuidPrefix},
    InfoTimestamp(Timestamp),

    // Entity Submessages
    AckNack { reader_id: EntityId, writer_id: EntityId, reader_sn_state: SequenceNumberSet, count: Count  },
    Data { reader_id: EntityId, writer_id: EntityId, writer_sn: SequenceNumber/*, inline_qos: Option<InlineQOS> */, serialized_payload: ArcBuffer  },
    // TODO: Data frag will require a 'buffer farm' concept so we can process multiple messages then form a single cache_change
    DataFrag { reader_id: EntityId, writer_id: EntityId, writer_sn: SequenceNumber, fragment_start_num: FragmentNumber, fragments_in_submessage: u16, data_size: u32, fragment_size: u16, /*, inline_qos: Option<InlineQOS>, */ serialized_payload: ArcBuffer },
    Gap { reader_id: EntityId, writer_id: EntityId, gap_start: SequenceNumber, gap_list: SequenceNumberSet },
    HeartBeat { reader_id: EntityId, writer_id: EntityId, first_sn: SequenceNumber, last_sn: SequenceNumber, count: Count },
    HeartbeatFrag { reader_id: EntityId, writer_id: EntityId, writer_sn: SequenceNumber, last_fragment_number: FragmentNumber, count: Count },
    NackFrag { reader_id: EntityId, writer_id: EntityId, writer_sn: SequenceNumber, fragment_number_state: FragmentNumberSet, count: Count },
    Pad
}

impl serde::Deserialize for SubmessageVariant {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: serde::Deserializer {
        let kind : SubmessageId = try!(serde::Deserialize::deserialize(deserializer));
        let _ : u8 = try!(serde::Deserialize::deserialize(deserializer));
        // len of message. TODO: use to confirm the proper number of bytes are read
        let _ : u32 = try!(serde::Deserialize::deserialize(deserializer));

        match kind {
            SubmessageId::INFO_TS => {
                // Wow, such terse
                Ok(SubmessageVariant::InfoTimestamp(try!(serde::Deserialize::deserialize(deserializer))))
            },
            SubmessageId::INFO_SRC => {
                Ok(SubmessageVariant::InfoSource{
                    protocol_version: try!(serde::Deserialize::deserialize(deserializer)),
                    vendor_id: try!(serde::Deserialize::deserialize(deserializer)),
                    guid_prefix: try!(serde::Deserialize::deserialize(deserializer))
                })
            },
            SubmessageId::INFO_REPLY => {
                Ok(SubmessageVariant::InfoReply{
                    unicast_locator_list: try!(serde::Deserialize::deserialize(deserializer))
                })
            },
            SubmessageId::INFO_DST => {
                Ok(SubmessageVariant::InfoDestination(try!(serde::Deserialize::deserialize(deserializer))))
            },
            SubmessageId::INFO_REPLY_IP4 => {
                Err(serde::Error::custom("we don't do ipv4 specialization yet"))
//                0x0f
            },

            SubmessageId::ACKNACK => {
                Ok(SubmessageVariant::AckNack {
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    reader_sn_state: try!(serde::Deserialize::deserialize(deserializer)),
                    count: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::DATA => {
                Ok(SubmessageVariant::Data {
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    serialized_payload: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::DATA_FRAG => {
                Ok(SubmessageVariant::DataFrag {
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_sn: try!(serde::Deserialize::deserialize(deserializer)),

                    fragment_start_num: try!(serde::Deserialize::deserialize(deserializer)),
                    fragments_in_submessage: try!(serde::Deserialize::deserialize(deserializer)),
                    data_size: try!(serde::Deserialize::deserialize(deserializer)),
                    fragment_size: try!(serde::Deserialize::deserialize(deserializer)),

                    serialized_payload: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::HEARTBEAT => {
                Ok(SubmessageVariant::HeartBeat{
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    first_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    last_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    count: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::HEARTBEAT_FRAG => {
                Ok(SubmessageVariant::HeartbeatFrag {
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    last_fragment_number: try!(serde::Deserialize::deserialize(deserializer)),
                    count: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::GAP => {
                Ok(SubmessageVariant::Gap{
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    gap_start: try!(serde::Deserialize::deserialize(deserializer)),
                    gap_list: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },

            SubmessageId::NACK_FRAG => {
                Ok(SubmessageVariant::NackFrag{
                    reader_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_id: try!(serde::Deserialize::deserialize(deserializer)),
                    writer_sn: try!(serde::Deserialize::deserialize(deserializer)),
                    fragment_number_state: try!(serde::Deserialize::deserialize(deserializer)),
                    count: try!(serde::Deserialize::deserialize(deserializer)),
                })
            },
            SubmessageId::PAD => {
                Ok(SubmessageVariant::Pad)
            }
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Debug,PartialEq)]
pub enum SubmessageId {
    PAD,
    ACKNACK,
    HEARTBEAT,
    GAP,
    INFO_TS,
    INFO_SRC,
    INFO_REPLY_IP4,
    INFO_DST,
    INFO_REPLY,
    NACK_FRAG,
    HEARTBEAT_FRAG,
    DATA,
    DATA_FRAG,
}

impl Serialize for SubmessageId {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let val = match *self {
            SubmessageId::PAD => 0x01, /* Pad */
            SubmessageId::ACKNACK => 0x06, /* AckNack */
            SubmessageId::HEARTBEAT => 0x07, /* Heartbeat */
            SubmessageId::GAP => 0x08, /* Gap */
            SubmessageId::INFO_TS => 0x09, /* InfoTimestamp */
            SubmessageId::INFO_SRC => 0x0c, /* InfoSource */
            SubmessageId::INFO_REPLY_IP4 => 0x0d, /* InfoReplyIp4 */
            SubmessageId::INFO_DST => 0x0e, /* InfoDestination */
            SubmessageId::INFO_REPLY => 0x0f, /* InfoReply */
            SubmessageId::NACK_FRAG => 0x12, /* NackFrag */
            SubmessageId::HEARTBEAT_FRAG => 0x13, /* HeartbeatFrag */
            SubmessageId::DATA => 0x15, /* Data */
            SubmessageId::DATA_FRAG => 0x16, /* DataFrag */
        };
        serializer.serialize_u8(val)
    }
}

impl serde::Deserialize for SubmessageId {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: serde::Deserializer {
        let byte : u8 = try!(serde::Deserialize::deserialize(deserializer));
        match byte {
            0x01 => Ok(SubmessageId::PAD), /* Pad */
            0x06 => Ok(SubmessageId::ACKNACK), /* AckNack */
            0x07 => Ok(SubmessageId::HEARTBEAT), /* Heartbeat */
            0x08 => Ok(SubmessageId::GAP), /* Gap */
            0x09 => Ok(SubmessageId::INFO_TS), /* InfoTimestamp */
            0x0c => Ok(SubmessageId::INFO_SRC), /* InfoSource */
            0x0d => Ok(SubmessageId::INFO_REPLY_IP4), /* InfoReplyIp4 */
            0x0e => Ok(SubmessageId::INFO_DST), /* InfoDestination */
            0x0f => Ok(SubmessageId::INFO_REPLY), /* InfoReply */
            0x12 => Ok(SubmessageId::NACK_FRAG), /* NackFrag */
            0x13 => Ok(SubmessageId::HEARTBEAT_FRAG), /* HeartbeatFrag */
            0x15 => Ok(SubmessageId::DATA), /* Data */
            0x16 => Ok(SubmessageId::DATA_FRAG), /* DataFrag */
            _ => Err(serde::Error::custom(format!("unknown type {:?}", byte))),
        }
    }
}

bitflags! {
    pub flags SubmessageFlags: u8 {
        const LITTLE_ENDIAN = 0x01,
        const ACK_NACK_FINAL_FLAG = 0x02,

        const DATA_INLINE_QOS = 0x02,
        const DATA_DATA = 0x04,
        const DATA_KEY = 0x08,
        const DATA_FRAG_INLINE_QOS = 0x02,
        // eh, will add more as-needed
    }
}

impl Serialize for Submessage {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        // Write the submessage id
        try!(self.id.serialize(serializer));

        // Write the submessage flags (aka, the endianness)
        let flags : u8 = match self.endianness {
            Endianness::Little => 1,
            Endianness::Big => 0
        };
        try!(serializer.serialize_u8(flags));

        try!(serializer.serialize_u32(self.buf.len() as u32));
        serializer.serialize_bytes(self.buf.buf())
    }
}<|endoftext|>


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

use ::engine::{ConfigManager, PluginManager};
use ::util::Logger;

use std::cell::RefCell;
use std::rc::Rc;
use std::boxed::Box;

/*===============================================================================================*/
/*------STATIC VARIABLES-------------------------------------------------------------------------*/
/*===============================================================================================*/

static mut APP_POINTER: Option <*mut App> = None;

/*===============================================================================================*/
/*------APP STRUCT-------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The app
///
/// This is the main control center of ionCore.
/// It is in charge of initialization, updating, and shutdown of all modules,
/// as well as the handing of any inter-module communication.
#[derive (Clone)]
pub struct App {

    // Public
    /// The config manager.
    pub config_manager: Rc<RefCell<ConfigManager>>,
    /// The plugin manager.
    pub plugin_manager: Rc<RefCell<PluginManager>>,
}

/*===============================================================================================*/
/*------APPVERSION PUBLIC STATIC METHODS---------------------------------------------------------*/
/*===============================================================================================*/

impl App {

    /// Initializes the app
    pub fn init () {

        // Check if not already initialized
        if !App::is_initialized () {

            Logger::init ("./ionCore.log", true).unwrap ();
            info! ("Initializing ionCore | Version: {}", env! ("CARGO_PKG_VERSION"));

            let ab = Box::new (App {config_manager: Rc::new (RefCell::new (ConfigManager::new ())),
                                    plugin_manager: Rc::new (RefCell::new (PluginManager::new ()))});

            unsafe {APP_POINTER = Some (Box::into_raw (ab))};
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Checks if the app has been initialized.
    ///
    /// # Return value
    /// A bool returning whether the app has been initialized.
    pub fn is_initialized () -> bool {

        unsafe {

            match APP_POINTER {

                Some (pointer) => !pointer.is_null (),
                None => false
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a pointer to the config manager instance
    ///
    /// # Examples
    /// ```
    /// # use ion_core::engine::App;
    /// #
    /// # App::init ();
    /// let cfg = App::get_config_manager ().unwrap ();
    /// println! ("{}", cfg.borrow ().config_dir);
    pub fn get_config_manager () -> Option<Rc<RefCell<ConfigManager>>> {

        // Check if app is initialized
        if App::is_initialized () {
            return Some (unsafe {&*APP_POINTER.unwrap ()}.config_manager.clone ());
        }

        None
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a pointer to the plugin manager instance
    pub fn get_plugin_manager () -> Option<Rc<RefCell<PluginManager>>> {

        // Check if app is initialized
        if App::is_initialized () {
            return Some (unsafe {&*APP_POINTER.unwrap ()}.plugin_manager.clone ());
        }

        None
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Releases the app instance.
    ///
    /// After this point, any app commands will be ignored.
    pub fn release () {

        // Check if app is initialized
        if App::is_initialized () {

            info! ("Shutting down ion Core.");

            unsafe {

                Box::from_raw (APP_POINTER.unwrap ());
                APP_POINTER = None;
            };
        }
    }
}
<commit_msg>Changed option to result<commit_after>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

use ::engine::{ConfigManager, PluginManager};
use ::util::Logger;

use std::cell::RefCell;
use std::rc::Rc;
use std::boxed::Box;

/*===============================================================================================*/
/*------STATIC VARIABLES-------------------------------------------------------------------------*/
/*===============================================================================================*/

static mut APP_POINTER: Option <*mut App> = None;

/*===============================================================================================*/
/*------APP STRUCT-------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The app
///
/// This is the main control center of ionCore.
/// It is in charge of initialization, updating, and shutdown of all modules,
/// as well as the handing of any inter-module communication.
#[derive (Clone)]
pub struct App {

    // Public
    /// The config manager.
    pub config_manager: Rc<RefCell<ConfigManager>>,
    /// The plugin manager.
    pub plugin_manager: Rc<RefCell<PluginManager>>,
}

/*===============================================================================================*/
/*------APPVERSION PUBLIC STATIC METHODS---------------------------------------------------------*/
/*===============================================================================================*/

impl App {

    /// Initializes the app
    pub fn init () {

        // Check if not already initialized
        if !App::is_initialized () {

            Logger::init ("./ionCore.log", true).unwrap ();
            info! ("Initializing ionCore | Version: {}", env! ("CARGO_PKG_VERSION"));

            let ab = Box::new (App {config_manager: Rc::new (RefCell::new (ConfigManager::new ())),
                                    plugin_manager: Rc::new (RefCell::new (PluginManager::new ()))});

            unsafe {APP_POINTER = Some (Box::into_raw (ab))};
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Checks if the app has been initialized.
    ///
    /// # Return value
    /// A bool returning whether the app has been initialized.
    pub fn is_initialized () -> bool {

        unsafe {

            match APP_POINTER {

                Some (pointer) => !pointer.is_null (),
                None => false
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a pointer to the config manager instance
    ///
    /// # Examples
    /// ```
    /// # use ion_core::engine::App;
    /// #
    /// # App::init ();
    /// let cfg = App::get_config_manager ().unwrap ();
    /// println! ("{}", cfg.borrow ().config_dir);
    pub fn get_config_manager () -> Result<Rc<RefCell<ConfigManager>>, ()> {

        // Check if app is initialized
        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()}.config_manager.clone ());
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a pointer to the plugin manager instance
    pub fn get_plugin_manager () -> Result<Rc<RefCell<PluginManager>>, ()> {

        // Check if app is initialized
        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()}.plugin_manager.clone ());
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Releases the app instance.
    ///
    /// After this point, any app commands will be ignored.
    pub fn release () {

        // Check if app is initialized
        if App::is_initialized () {

            info! ("Shutting down ion Core.");

            unsafe {

                Box::from_raw (APP_POINTER.unwrap ());
                APP_POINTER = None;
            };
        }
    }
}
<|endoftext|>


<commit_before>use grid::Grid;

pub trait Engine {
    fn set_grid<T: Grid>(&self, grid: T);
    fn run(&self);
}<commit_msg>Iter requirement.<commit_after>mod sequential;

use grid::Grid;

use self::sequential::Sequential;

pub trait Engine {
    fn new<T: Grid + Iterator>(grid: T) -> Self;
    fn run(&self);
}<|endoftext|>


<commit_before>//! Engines provide source analysis for rust code
use std::path::Path;

/// This module's Error and Result types
mod error;
pub use self::error::{Error, Result};

/// Provide completions, definitions, and analysis of rust source code
pub trait SemanticEngine {
    /// Find the definition for the item under the cursor
    fn find_definition(&self, context: &Context) -> Result<Option<Definition>>;

    // Get a list of completions for the item under the cursor
    // fn complete(loc: &FileLocation) -> io::Result<Vec<Completion>>;
}

/// Source file and type information for a found definition
#[derive(Debug, RustcEncodable)]
pub struct Definition {
    pub position: CursorPosition,
    pub text: String,
    pub text_context: String,
    pub dtype: String,
    pub file_path: String,
}

/// Context for a given operation.
///
/// All operations require a buffer holding the contents of a file, the file's absolute path, and a
/// cursor position to fully specify the request. This object holds all of those items.
#[derive(Debug, RustcEncodable)]
pub struct Context<'a> {
    pub contents: &'a str,
    pub cursor: CursorPosition,
    pub file_path: &'a str,
}

impl<'a> Context<'a> {
    pub fn new(contents: &'a str, position: CursorPosition, file_path: &'a str) -> Context<'a> {
        Context {
            contents: contents,
            cursor: position,
            file_path: file_path,
        }
    }

    pub fn path(&'a self) -> &'a Path {
        &Path::new(self.file_path)
    }
}

/// Position of the cursor in a text file
///
/// Similar to a point, it has two coordinates `line` and `col`.
#[derive(Debug, RustcEncodable)]
pub struct CursorPosition {
    pub line: usize,
    pub col: usize,
}

pub mod racer;
pub use self::racer::Racer;

<commit_msg>Remove unused derivations for engine types<commit_after>//! Engines provide source analysis for rust code
use std::path::Path;

/// This module's Error and Result types
mod error;
pub use self::error::{Error, Result};

/// Provide completions, definitions, and analysis of rust source code
pub trait SemanticEngine {
    /// Find the definition for the item under the cursor
    fn find_definition(&self, context: &Context) -> Result<Option<Definition>>;

    // Get a list of completions for the item under the cursor
    // fn complete(loc: &FileLocation) -> io::Result<Vec<Completion>>;
}

/// Source file and type information for a found definition
#[derive(Debug)]
pub struct Definition {
    pub position: CursorPosition,
    pub text: String,
    pub text_context: String,
    pub dtype: String,
    pub file_path: String,
}

/// Context for a given operation.
///
/// All operations require a buffer holding the contents of a file, the file's absolute path, and a
/// cursor position to fully specify the request. This object holds all of those items.
#[derive(Debug)]
pub struct Context<'a> {
    pub contents: &'a str,
    pub cursor: CursorPosition,
    pub file_path: &'a str,
}

impl<'a> Context<'a> {
    pub fn new(contents: &'a str, position: CursorPosition, file_path: &'a str) -> Context<'a> {
        Context {
            contents: contents,
            cursor: position,
            file_path: file_path,
        }
    }

    pub fn path(&'a self) -> &'a Path {
        &Path::new(self.file_path)
    }
}

/// Position of the cursor in a text file
///
/// Similar to a point, it has two coordinates `line` and `col`.
#[derive(Debug)]
pub struct CursorPosition {
    pub line: usize,
    pub col: usize,
}

pub mod racer;
pub use self::racer::Racer;

<|endoftext|>