<commit_before>use clap;
use std;
use std::env;
use std::path::PathBuf;
use errors::*;
use dir;

pub use clap::ArgMatches;

pub fn app<'a, 'b>() -> clap::App<'a, 'b> {
    clap::App::new("to")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Bookmark directories")

        // User friendly info! output.
        .arg(clap::Arg::with_name("verbose")
            .long("verbose")
            .short("v")
            .help("Verbose log output")
            .takes_value(false))

        .arg(clap::Arg::with_name("config")
            .long("config")
            .short("c")
            .help("Config dir, defaults to ~/.to")
            .takes_value(true))

        // Positional arguments.
        .arg(clap::Arg::with_name("NAME")
            .help("Name of the bookamrk")
            .index(1))
        .arg(clap::Arg::with_name("DIRECTORY")
            .help("Path of the bookamrk")
            .index(2))

        // Flags.
        .arg(clap::Arg::with_name("info")
            .long("info")
            .short("i")
            .help("Show bookmark information")
            .takes_value(false))
        .arg(clap::Arg::with_name("save")
            .long("save")
            .short("s")
            .help("Save bookmark")
            .takes_value(false))
        .arg(clap::Arg::with_name("delete")
            .long("delete")
            .short("d")
            .help("Delete bookmark")
            .takes_value(false)
            .requires("NAME"))
        .arg(clap::Arg::with_name("list")
            .long("list")
            .short("l")
            .help("List all bookmarks")
            .takes_value(false))
        .arg(clap::Arg::with_name("initialize")
            .long("init")
            .help("Echo initialization script")
            .takes_value(false)
            .conflicts_with_all(&[
                "NAME",
                "DIRECTORY",
                "get",
                "put",
                "delete",
                "list",
            ]))
}

#[derive(Debug, PartialEq)]
pub enum Action {
    Delete,
    Info,
    List,
    Save,
    Pathname,
}

pub struct Options {
    pub verbose: bool,
    pub initialize: bool,
    pub action: Action,
    pub name: String,
    pub path: PathBuf,
    pub config: PathBuf,
}

impl Options {
    /// Creates a new instance of Options from clap::ArgMatches.
    ///
    /// # Examples:
    ///
    /// ```
    /// use to::cli;
    ///
    /// let matches = cli::app().get_matches_from(vec![""]);
    /// let options = cli::Options::new(matches).unwrap();
    ///
    /// assert_eq!(options.verbose, false);
    /// assert_eq!(options.initialize, false);
    /// assert_eq!(options.action, cli::Action::Pathname);
    /// ```
    pub fn new(matches: clap::ArgMatches) -> Result<Options> {
        let (delete, info, list, save) = (
            matches.is_present("delete"),
            matches.is_present("info"),
            matches.is_present("list"),
            matches.is_present("save"),
        );

        let action = match (delete, info, list, save) {
            (true, _, _, _) => Action::Delete,
            (_, true, _, _) => Action::Info,
            (_, _, true, _) => Action::List,
            (_, _, _, true) => Action::Save,
            _ => Action::Pathname,
        };

        let directory = matches.value_of("DIRECTORY").map(PathBuf::from);
        let path = match directory {
            Some(value) => try!(dir::resolve(value)),
            None => try!(env::current_dir()),
        };

        let name = matches
            .value_of("NAME")
            .map(normalize)
            .unwrap_or(try!(dir::basename(&path)));

        Ok(Options {
            action: action,
            config: try!(config(matches.value_of("config"))),
            path: path,
            initialize: matches.is_present("initialize"),
            name: name,
            verbose: matches.is_present("verbose"),
        })
    }
}

// Normalize CLI text input.
//
// Will convert to lowercase, remove whitespace, and trim trailing slashes sometimes added by tab
// completion.
fn normalize(string: &str) -> String {
    string
        .trim()
        .trim_right_matches(std::path::MAIN_SEPARATOR)
        .to_lowercase()
}

fn config(value: Option<&str>) -> Result<PathBuf> {
    value
        .map(PathBuf::from)
        .or_else(|| {
            env::home_dir().map(|mut home| {
                home.push(".to");
                home
            })
        })
        .ok_or_else(|| ErrorKind::ConfigError.into())
}

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

    #[test]
    fn normalize_name_input() {
        assert_eq!(normalize("trim-trailing/"), "trim-trailing");
        assert_eq!(normalize("LOWERCASE"), "lowercase");
        assert_eq!(normalize("  spaces "), "spaces");
    }
}
<commit_msg>Increase coverage?<commit_after>use clap;
use std;
use std::env;
use std::path::PathBuf;
use errors::*;
use dir;

pub use clap::ArgMatches;

pub fn app<'a, 'b>() -> clap::App<'a, 'b> {
    clap::App::new("to")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Bookmark directories")

        // User friendly info! output.
        .arg(clap::Arg::with_name("verbose")
            .long("verbose")
            .short("v")
            .help("Verbose log output")
            .takes_value(false))

        .arg(clap::Arg::with_name("config")
            .long("config")
            .short("c")
            .help("Config dir, defaults to ~/.to")
            .takes_value(true))

        // Positional arguments.
        .arg(clap::Arg::with_name("NAME")
            .help("Name of the bookamrk")
            .index(1))
        .arg(clap::Arg::with_name("DIRECTORY")
            .help("Path of the bookamrk")
            .index(2))

        // Flags.
        .arg(clap::Arg::with_name("info")
            .long("info")
            .short("i")
            .help("Show bookmark information")
            .takes_value(false))
        .arg(clap::Arg::with_name("save")
            .long("save")
            .short("s")
            .help("Save bookmark")
            .takes_value(false))
        .arg(clap::Arg::with_name("delete")
            .long("delete")
            .short("d")
            .help("Delete bookmark")
            .takes_value(false)
            .requires("NAME"))
        .arg(clap::Arg::with_name("list")
            .long("list")
            .short("l")
            .help("List all bookmarks")
            .takes_value(false))
        .arg(clap::Arg::with_name("initialize")
            .long("init")
            .help("Echo initialization script")
            .takes_value(false)
            .conflicts_with_all(&[
                "NAME",
                "DIRECTORY",
                "get",
                "put",
                "delete",
                "list"]))
}

#[derive(Debug, PartialEq)]
pub enum Action {
    Delete,
    Info,
    List,
    Save,
    Pathname,
}

pub struct Options {
    pub verbose: bool,
    pub initialize: bool,
    pub action: Action,
    pub name: String,
    pub path: PathBuf,
    pub config: PathBuf,
}

impl Options {
    /// Creates a new instance of Options from clap::ArgMatches.
    ///
    /// # Examples:
    ///
    /// ```
    /// use to::cli;
    ///
    /// let matches = cli::app().get_matches_from(vec![""]);
    /// let options = cli::Options::new(matches).unwrap();
    ///
    /// assert_eq!(options.verbose, false);
    /// assert_eq!(options.initialize, false);
    /// assert_eq!(options.action, cli::Action::Pathname);
    /// ```
    pub fn new(matches: clap::ArgMatches) -> Result<Options> {
        let (delete, info, list, save) = (
            matches.is_present("delete"),
            matches.is_present("info"),
            matches.is_present("list"),
            matches.is_present("save"),
        );

        let action = match (delete, info, list, save) {
            (true, _, _, _) => Action::Delete,
            (_, true, _, _) => Action::Info,
            (_, _, true, _) => Action::List,
            (_, _, _, true) => Action::Save,
            _ => Action::Pathname,
        };

        let directory = matches.value_of("DIRECTORY").map(PathBuf::from);
        let path = match directory {
            Some(value) => try!(dir::resolve(value)),
            None => try!(env::current_dir()),
        };

        let name = matches
            .value_of("NAME")
            .map(normalize)
            .unwrap_or(try!(dir::basename(&path)));

        Ok(Options {
            action: action,
            config: try!(config(matches.value_of("config"))),
            path: path,
            initialize: matches.is_present("initialize"),
            name: name,
            verbose: matches.is_present("verbose")})
    }
}

// Normalize CLI text input.
//
// Will convert to lowercase, remove whitespace, and trim trailing slashes sometimes added by tab
// completion.
fn normalize(string: &str) -> String {
    string
        .trim()
        .trim_right_matches(std::path::MAIN_SEPARATOR)
        .to_lowercase()
}

fn config(value: Option<&str>) -> Result<PathBuf> {
    value
        .map(PathBuf::from)
        .or_else(|| {
            env::home_dir().map(|mut home| {
                home.push(".to");
                home
            })
        })
        .ok_or_else(|| ErrorKind::ConfigError.into())
}

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

    #[test]
    fn normalize_name_input() {
        assert_eq!(normalize("trim-trailing/"), "trim-trailing");
        assert_eq!(normalize("LOWERCASE"), "lowercase");
        assert_eq!(normalize("  spaces "), "spaces");
    }
}
<|endoftext|>


<commit_before>use clap::{
    arg_enum, crate_version, value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches,
    SubCommand,
};

arg_enum! {
    #[derive(Copy, Clone, Debug, PartialEq)]
    pub enum Format {
        List,
        Json,
    }
}

arg_enum! {
    #[derive(Copy, Clone, Debug, PartialEq)]
    pub enum Color {
        Auto,
        Never,
        Always
    }
}

/// Options from CLI arguments
#[derive(Debug)]
pub struct Options {
    pub format: Format,
    pub color: Color,
    pub features: Vec<String>,
    pub ignore: Vec<String>,
    pub exclude: Vec<String>,
    pub manifest_path: Option<String>,
    pub quiet: bool,
    pub verbose: u64,
    pub exit_code: i32,
    pub packages: Vec<String>,
    pub root: Option<String>,
    pub depth: Option<i32>,
    pub root_deps_only: bool,
    pub workspace: bool,
    pub aggressive: bool,
    pub offline: bool,
}

impl Options {
    pub fn all_features(&self) -> bool { self.features.is_empty() }

    pub fn no_default_features(&self) -> bool {
        !(self.features.is_empty() || self.features.contains(&"default".to_owned()))
    }

    pub fn locked(&self) -> bool { false }

    pub fn frozen(&self) -> bool { false }
}

impl<'a> From<&ArgMatches<'a>> for Options {
    fn from(m: &ArgMatches<'a>) -> Self {
        let mut opts = Options {
            format: value_t_or_exit!(m.value_of("format"), Format),
            color: value_t_or_exit!(m.value_of("color"), Color),
            features: m
                .values_of("features")
                .map(|vals| {
                    vals.flat_map(|x| x.split_ascii_whitespace().collect::<Vec<_>>())
                        .map(ToOwned::to_owned)
                        .collect()
                })
                .unwrap_or_else(Vec::new),
            ignore: m
                .values_of("ignore")
                .map(|vals| {
                    vals.flat_map(|x| x.split_ascii_whitespace().collect::<Vec<_>>())
                        .map(ToOwned::to_owned)
                        .collect()
                })
                .unwrap_or_else(Vec::new),
            exclude: m
                .values_of("exclude")
                .map(|vals| {
                    vals.flat_map(|x| x.split_ascii_whitespace().collect::<Vec<_>>())
                        .map(ToOwned::to_owned)
                        .collect()
                })
                .unwrap_or_else(Vec::new),
            manifest_path: m.value_of("manifest-path").map(ToOwned::to_owned),
            quiet: m.is_present("quiet"),
            verbose: m.occurrences_of("verbose"),
            exit_code: value_t!(m, "exit-code", i32).ok().unwrap_or(0),
            packages: m
                .values_of("packages")
                .map(|vals| {
                    vals.flat_map(|x| x.split_ascii_whitespace().collect::<Vec<_>>())
                        .map(ToOwned::to_owned)
                        .collect::<Vec<_>>()
                })
                .unwrap_or_else(Vec::new),
            root: m.value_of("root").map(ToOwned::to_owned),
            depth: value_t!(m, "depth", i32).ok(),
            root_deps_only: m.is_present("root-deps-only"),
            workspace: m.is_present("workspace"),
            aggressive: m.is_present("aggressive"),
            offline: m.is_present("offline"),
        };

        if m.is_present("root-deps-only") {
            opts.depth = Some(1);
        }

        opts
    }
}

pub fn parse() -> Options {
    let matches = App::new("cargo-outdated")
        .bin_name("cargo")
        .setting(AppSettings::SubcommandRequired)
        .subcommand(
            SubCommand::with_name("outdated")
                .setting(AppSettings::UnifiedHelpMessage)
                .about("Displays information about project dependency versions")
                .version(crate_version!())
                .arg(
                    Arg::with_name("aggressive")
                        .short("a")
                        .long("aggresssive")
                        .help("Ignores channels for latest updates"),
                )
                .arg(
                    Arg::with_name("quiet")
                        .short("q")
                        .long("quiet")
                        .help("Suppresses warnings"),
                )
                .arg(
                    Arg::with_name("root-deps-only")
                        .short("R")
                        .long("root-deps-only")
                        .help("Only check root dependencies (Equivalent to --depth=1)"),
                )
                .arg(
                    Arg::with_name("workspace")
                        .short("w")
                        .long("workspace")
                        .help("Checks updates for all workspace members rather than only the root package"),
                )
                .arg(
                    Arg::with_name("offline")
                        .short("o")
                        .long("offline")
                        .help("Run without accessing the network (useful for testing w/ local registries)"),
                )
                .arg(
                    Arg::with_name("format")
                        .long("format")
                        .default_value("list")
                        .case_insensitive(true)
                        .possible_values(&Format::variants())
                        .value_name("FORMAT")
                        .help("Output formatting"),
                )
                .arg(
                    Arg::with_name("ignore")
                        .short("i")
                        .long("ignore")
                        .help("Dependencies to not print in the output (comma separated or one per '--ignore' argument)")
                        .value_delimiter(",")
                        .number_of_values(1)
                        .multiple(true)
                        .value_name("DEPENDENCIES"),
                )
                .arg(
                    Arg::with_name("exclude")
                        .short("x")
                        .long("exclude")
                        .help("Dependencies to exclude from building (comma separated or one per '--exclude' argument)")
                        .value_delimiter(",")
                        .multiple(true)
                        .number_of_values(1)
                        .value_name("DEPENDENCIES"),
                )
                .arg(
                    Arg::with_name("verbose")
                        .short("v")
                        .long("verbose")
                        .multiple(true)
                        .help("Use verbose output")
                )
                .arg(
                    Arg::with_name("color")
                        .long("color")
                        .possible_values(&Color::variants())
                        .default_value("auto")
                        .value_name("COLOR")
                        .case_insensitive(true)
                        .help("Output coloring")
                )
                .arg(
                    Arg::with_name("depth")
                        .short("d")
                        .long("depth")
                        .value_name("NUM")
                        .help("How deep in the dependency chain to search (Defaults to all dependencies when omitted)")
                )
                .arg(
                    Arg::with_name("exit-code")
                        .long("exit-code")
                        .help("The exit code to return on new versions found")
                        .default_value("0")
                        .value_name("NUM"))
                .arg(
                    Arg::with_name("manifest-path")
                        .short("m")
                        .long("manifest-path")
                        .help("Path to the Cargo.toml file to use (Defaults to Cargo.toml in project root)")
                        .value_name("PATH"))
                .arg(
                    Arg::with_name("root")
                        .short("r")
                        .long("root")
                        .help("Package to treat as the root package")
                        .value_name("ROOT"))
                .arg(
                    Arg::with_name("packages")
                        .short("p")
                        .long("packages")
                        .help("Packages to inspect for updates (comma separated or one per '--packages' argument)")
                        .value_delimiter(",")
                        .number_of_values(1)
                        .multiple(true)
                        .value_name("PKGS"))
                .arg(
                    Arg::with_name("features")
                        .long("features")
                        .value_delimiter(",")
                        .help("Space-separated list of features")
                        .multiple(true)
                        .number_of_values(1)
                        .value_name("FEATURES"))
            )
        .get_matches();

    Options::from(matches.subcommand_matches("outdated").unwrap())
}
<commit_msg>tests: adds cli ux tests for clap<commit_after>use clap::{
    arg_enum, crate_version, value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches,
    SubCommand,
};

arg_enum! {
    #[derive(Copy, Clone, Debug, PartialEq)]
    pub enum Format {
        List,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self { Format::List }
}

arg_enum! {
    #[derive(Copy, Clone, Debug, PartialEq)]
    pub enum Color {
        Auto,
        Never,
        Always
    }
}

impl Default for Color {
    fn default() -> Self { Color::Auto }
}

/// Options from CLI arguments
#[derive(Debug, PartialEq, Default)]
pub struct Options {
    pub format: Format,
    pub color: Color,
    pub features: Vec<String>,
    pub ignore: Vec<String>,
    pub exclude: Vec<String>,
    pub manifest_path: Option<String>,
    pub quiet: bool,
    pub verbose: u64,
    pub exit_code: i32,
    pub packages: Vec<String>,
    pub root: Option<String>,
    pub depth: Option<i32>,
    pub root_deps_only: bool,
    pub workspace: bool,
    pub aggressive: bool,
    pub offline: bool,
}

impl Options {
    pub fn all_features(&self) -> bool { self.features.is_empty() }

    pub fn no_default_features(&self) -> bool {
        !(self.features.is_empty() || self.features.contains(&"default".to_owned()))
    }

    pub fn locked(&self) -> bool { false }

    pub fn frozen(&self) -> bool { false }
}

impl<'a> From<&ArgMatches<'a>> for Options {
    fn from(m: &ArgMatches<'a>) -> Self {
        let mut opts = Options {
            format: value_t_or_exit!(m.value_of("format"), Format),
            color: value_t_or_exit!(m.value_of("color"), Color),
            features: m
                .values_of("features")
                .map(|vals| {
                    vals.flat_map(|x| x.split_ascii_whitespace().collect::<Vec<_>>())
                        .map(ToOwned::to_owned)
                        .collect()
                })
                .unwrap_or_else(Vec::new),
            ignore: m
                .values_of("ignore")
                .map(|vals| {
                    vals.flat_map(|x| x.split_ascii_whitespace().collect::<Vec<_>>())
                        .map(ToOwned::to_owned)
                        .collect()
                })
                .unwrap_or_else(Vec::new),
            exclude: m
                .values_of("exclude")
                .map(|vals| {
                    vals.flat_map(|x| x.split_ascii_whitespace().collect::<Vec<_>>())
                        .map(ToOwned::to_owned)
                        .collect()
                })
                .unwrap_or_else(Vec::new),
            manifest_path: m.value_of("manifest-path").map(ToOwned::to_owned),
            quiet: m.is_present("quiet"),
            verbose: m.occurrences_of("verbose"),
            exit_code: value_t!(m, "exit-code", i32).ok().unwrap_or(0),
            packages: m
                .values_of("packages")
                .map(|vals| {
                    vals.flat_map(|x| x.split_ascii_whitespace().collect::<Vec<_>>())
                        .map(ToOwned::to_owned)
                        .collect::<Vec<_>>()
                })
                .unwrap_or_else(Vec::new),
            root: m.value_of("root").map(ToOwned::to_owned),
            depth: value_t!(m, "depth", i32).ok(),
            root_deps_only: m.is_present("root-deps-only"),
            workspace: m.is_present("workspace"),
            aggressive: m.is_present("aggressive"),
            offline: m.is_present("offline"),
        };

        if m.is_present("root-deps-only") {
            opts.depth = Some(1);
        }

        opts
    }
}

fn build() -> App<'static, 'static> {
    App::new("cargo-outdated")
        .bin_name("cargo")
        .setting(AppSettings::SubcommandRequired)
        .subcommand(
            SubCommand::with_name("outdated")
                .setting(AppSettings::UnifiedHelpMessage)
                .about("Displays information about project dependency versions")
                .version(crate_version!())
                .arg(
                    Arg::with_name("aggressive")
                        .short("a")
                        .long("aggresssive")
                        .help("Ignores channels for latest updates"),
                )
                .arg(
                    Arg::with_name("quiet")
                        .short("q")
                        .long("quiet")
                        .help("Suppresses warnings"),
                )
                .arg(
                    Arg::with_name("root-deps-only")
                        .short("R")
                        .long("root-deps-only")
                        .help("Only check root dependencies (Equivalent to --depth=1)"),
                )
                .arg(
                    Arg::with_name("workspace")
                        .short("w")
                        .long("workspace")
                        .help("Checks updates for all workspace members rather than only the root package"),
                )
                .arg(
                    Arg::with_name("offline")
                        .short("o")
                        .long("offline")
                        .help("Run without accessing the network (useful for testing w/ local registries)"),
                )
                .arg(
                    Arg::with_name("format")
                        .long("format")
                        .default_value("list")
                        .case_insensitive(true)
                        .possible_values(&Format::variants())
                        .value_name("FORMAT")
                        .help("Output formatting"),
                )
                .arg(
                    Arg::with_name("ignore")
                        .short("i")
                        .long("ignore")
                        .help("Dependencies to not print in the output (comma separated or one per '--ignore' argument)")
                        .value_delimiter(",")
                        .number_of_values(1)
                        .multiple(true)
                        .value_name("DEPENDENCIES"),
                )
                .arg(
                    Arg::with_name("exclude")
                        .short("x")
                        .long("exclude")
                        .help("Dependencies to exclude from building (comma separated or one per '--exclude' argument)")
                        .value_delimiter(",")
                        .multiple(true)
                        .number_of_values(1)
                        .value_name("DEPENDENCIES"),
                )
                .arg(
                    Arg::with_name("verbose")
                        .short("v")
                        .long("verbose")
                        .multiple(true)
                        .help("Use verbose output")
                )
                .arg(
                    Arg::with_name("color")
                        .long("color")
                        .possible_values(&Color::variants())
                        .default_value("auto")
                        .value_name("COLOR")
                        .case_insensitive(true)
                        .help("Output coloring")
                )
                .arg(
                    Arg::with_name("depth")
                        .short("d")
                        .long("depth")
                        .value_name("NUM")
                        .help("How deep in the dependency chain to search (Defaults to all dependencies when omitted)")
                )
                .arg(
                    Arg::with_name("exit-code")
                        .long("exit-code")
                        .help("The exit code to return on new versions found")
                        .default_value("0")
                        .value_name("NUM"))
                .arg(
                    Arg::with_name("manifest-path")
                        .short("m")
                        .long("manifest-path")
                        .help("Path to the Cargo.toml file to use (Defaults to Cargo.toml in project root)")
                        .value_name("PATH"))
                .arg(
                    Arg::with_name("root")
                        .short("r")
                        .long("root")
                        .help("Package to treat as the root package")
                        .value_name("ROOT"))
                .arg(
                    Arg::with_name("packages")
                        .short("p")
                        .long("packages")
                        .help("Packages to inspect for updates (comma separated or one per '--packages' argument)")
                        .value_delimiter(",")
                        .number_of_values(1)
                        .multiple(true)
                        .value_name("PKGS"))
                .arg(
                    Arg::with_name("features")
                        .long("features")
                        .value_delimiter(",")
                        .help("Space-separated list of features")
                        .multiple(true)
                        .number_of_values(1)
                        .value_name("FEATURES"))
            )
}

pub fn parse() -> Options {
    let matches = build().get_matches();

    Options::from(matches.subcommand_matches("outdated").unwrap())
}

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

    fn options(args: &[&str]) -> Options {
        let mut argv = vec!["cargo", "outdated"];
        argv.extend(args);
        let m = build().get_matches_from(argv);
        Options::from(m.subcommand_matches("outdated").unwrap())
    }

    fn options_fail(args: &[&str]) -> clap::Result<ArgMatches<'static>> {
        let mut argv = vec!["cargo", "outdated"];
        argv.extend(args);
        build().get_matches_from_safe(argv)
    }

    #[test]
    fn default() {
        let opts = options(&[]);
        assert_eq!(Options::default(), opts)
    }

    #[test]
    fn root_only() {
        let opts = options(&["--root-deps-only"]);
        assert_eq!(
            Options {
                depth: Some(1),
                root_deps_only: true,
                ..Options::default()
            },
            opts
        )
    }

    #[test]
    fn features() {
        let opts1 = options(&["--features=one,two,three"]);
        let opts2 = options(&["--features", "one,two,three"]);
        let opts3 = options(&["--features", "one two three"]);
        let opts4 = options(&[
            "--features",
            "one",
            "--features",
            "two",
            "--features",
            "three",
        ]);
        let opts5 = options(&["--features", "one", "--features", "two,three"]);

        let correct = Options {
            features: vec!["one".into(), "two".into(), "three".into()],
            ..Options::default()
        };

        assert_eq!(correct, opts1);
        assert_eq!(correct, opts2);
        assert_eq!(correct, opts3);
        assert_eq!(correct, opts4);
        assert_eq!(correct, opts5);
    }

    #[test]
    fn features_fail() {
        let res = options_fail(&["--features", "one", "two"]);
        assert!(res.is_err());
        assert_eq!(
            res.as_ref().unwrap_err().kind,
            clap::ErrorKind::UnknownArgument,
            "{:?}",
            res.as_ref().unwrap_err().kind
        );
    }

    #[test]
    fn exclude() {
        let opts1 = options(&["--exclude=one,two,three"]);
        let opts2 = options(&["--exclude", "one,two,three"]);
        let opts3 = options(&["--exclude", "one two three"]);
        let opts4 = options(&["--exclude", "one", "--exclude", "two", "--exclude", "three"]);
        let opts5 = options(&["--exclude", "one", "--exclude", "two,three"]);
        let correct = Options {
            exclude: vec!["one".into(), "two".into(), "three".into()],
            ..Options::default()
        };

        assert_eq!(correct, opts1);
        assert_eq!(correct, opts2);
        assert_eq!(correct, opts3);
        assert_eq!(correct, opts4);
        assert_eq!(correct, opts5);
    }

    #[test]
    fn exclude_fail() {
        let res = options_fail(&["--exclude", "one", "two"]);
        assert!(res.is_err());
        assert_eq!(
            res.as_ref().unwrap_err().kind,
            clap::ErrorKind::UnknownArgument,
            "{:?}",
            res.as_ref().unwrap_err().kind
        );
    }

    #[test]
    fn ignore() {
        let opts1 = options(&["--ignore=one,two,three"]);
        let opts2 = options(&["--ignore", "one,two,three"]);
        let opts3 = options(&["--ignore", "one two three"]);
        let opts4 = options(&["--ignore", "one", "--ignore", "two", "--ignore", "three"]);
        let opts5 = options(&["--ignore", "one", "--ignore", "two,three"]);
        let correct = Options {
            ignore: vec!["one".into(), "two".into(), "three".into()],
            ..Options::default()
        };

        assert_eq!(correct, opts1);
        assert_eq!(correct, opts2);
        assert_eq!(correct, opts3);
        assert_eq!(correct, opts4);
        assert_eq!(correct, opts5);
    }

    #[test]
    fn ignore_fail() {
        let res = options_fail(&["--ignore", "one", "two"]);
        assert!(res.is_err());
        assert_eq!(
            res.as_ref().unwrap_err().kind,
            clap::ErrorKind::UnknownArgument,
            "{:?}",
            res.as_ref().unwrap_err().kind
        );
    }

    #[test]
    fn verbose() {
        let opts1 = options(&["--verbose", "--verbose", "--verbose"]);
        let correct = Options {
            verbose: 3,
            ..Options::default()
        };

        assert_eq!(correct, opts1);
    }

    #[test]
    fn packages() {
        let opts1 = options(&["--packages", "one,two"]);
        let opts2 = options(&["--packages", "one two"]);
        let opts3 = options(&["--packages", "one", "--packages", "two"]);
        let correct = Options {
            packages: vec!["one".into(), "two".into()],
            ..Options::default()
        };

        assert_eq!(correct, opts1);
        assert_eq!(correct, opts2);
        assert_eq!(correct, opts3);
    }

    #[test]
    fn packages_fail() {
        let res = options_fail(&["--packages", "one", "two"]);
        assert!(res.is_err());
        assert_eq!(
            res.as_ref().unwrap_err().kind,
            clap::ErrorKind::UnknownArgument,
            "{:?}",
            res.as_ref().unwrap_err().kind
        );
    }

    #[test]
    fn format_case() {
        let opts1 = options(&["--format", "JsOn"]);
        let correct = Options {
            format: Format::Json,
            ..Options::default()
        };

        assert_eq!(correct, opts1);
    }

    #[test]
    fn format_unknown() {
        let res = options_fail(&["--format", "foobar"]);
        assert!(res.is_err());
        assert_eq!(
            res.as_ref().unwrap_err().kind,
            clap::ErrorKind::InvalidValue,
            "{:?}",
            res.as_ref().unwrap_err().kind
        );
    }

    #[test]
    fn color_case() {
        let opts1 = options(&["--color", "NeVeR"]);
        let correct = Options {
            color: Color::Never,
            ..Options::default()
        };

        assert_eq!(correct, opts1);
    }

    #[test]
    fn color_unknown() {
        let res = options_fail(&["--color", "foobar"]);
        assert!(res.is_err());
        assert_eq!(
            res.as_ref().unwrap_err().kind,
            clap::ErrorKind::InvalidValue,
            "{:?}",
            res.as_ref().unwrap_err().kind
        );
    }
}
<|endoftext|>


<commit_before>/// Calculates the 32bit crc from a given set of data. It does not appear to
/// be the typical crc calculation and may be specific to Rocket League and/or
/// Unreal Engine. Implementation is close, but not the same as the crc create
pub fn calc_crc(data: &[u8]) -> u32 {
    !data.iter().fold(!0xefcb_f201, |acc, &x| {
        (acc << 8) ^ (TABLE[((u32::from(x)) ^ (acc >> 24)) as usize])
    })
}

/// Precomputed crc table. It is extremely close to IEEE housed in the
/// crc crate, but they are not interchangeable. Still need to determine
/// the differences. Copied from the Octane project.
const TABLE: [u32; 256] = [
    0x0000_0000,
    0x04c1_1db7,
    0x0982_3b6e,
    0x0d43_26d9,
    0x1304_76dc,
    0x17c5_6b6b,
    0x1a86_4db2,
    0x1e47_5005,
    0x2608_edb8,
    0x22c9_f00f,
    0x2f8a_d6d6,
    0x2b4b_cb61,
    0x350c_9b64,
    0x31cd_86d3,
    0x3c8e_a00a,
    0x384f_bdbd,
    0x4c11_db70,
    0x48d0_c6c7,
    0x4593_e01e,
    0x4152_fda9,
    0x5f15_adac,
    0x5bd4_b01b,
    0x5697_96c2,
    0x5256_8b75,
    0x6a19_36c8,
    0x6ed8_2b7f,
    0x639b_0da6,
    0x675a_1011,
    0x791d_4014,
    0x7ddc_5da3,
    0x709f_7b7a,
    0x745e_66cd,
    0x9823_b6e0,
    0x9ce2_ab57,
    0x91a1_8d8e,
    0x9560_9039,
    0x8b27_c03c,
    0x8fe6_dd8b,
    0x82a5_fb52,
    0x8664_e6e5,
    0xbe2b_5b58,
    0xbaea_46ef,
    0xb7a9_6036,
    0xb368_7d81,
    0xad2f_2d84,
    0xa9ee_3033,
    0xa4ad_16ea,
    0xa06c_0b5d,
    0xd432_6d90,
    0xd0f3_7027,
    0xddb0_56fe,
    0xd971_4b49,
    0xc736_1b4c,
    0xc3f7_06fb,
    0xceb4_2022,
    0xca75_3d95,
    0xf23a_8028,
    0xf6fb_9d9f,
    0xfbb8_bb46,
    0xff79_a6f1,
    0xe13e_f6f4,
    0xe5ff_eb43,
    0xe8bc_cd9a,
    0xec7d_d02d,
    0x3486_7077,
    0x3047_6dc0,
    0x3d04_4b19,
    0x39c5_56ae,
    0x2782_06ab,
    0x2343_1b1c,
    0x2e00_3dc5,
    0x2ac1_2072,
    0x128e_9dcf,
    0x164f_8078,
    0x1b0c_a6a1,
    0x1fcd_bb16,
    0x018a_eb13,
    0x054b_f6a4,
    0x0808_d07d,
    0x0cc9_cdca,
    0x7897_ab07,
    0x7c56_b6b0,
    0x7115_9069,
    0x75d4_8dde,
    0x6b93_dddb,
    0x6f52_c06c,
    0x6211_e6b5,
    0x66d0_fb02,
    0x5e9f_46bf,
    0x5a5e_5b08,
    0x571d_7dd1,
    0x53dc_6066,
    0x4d9b_3063,
    0x495a_2dd4,
    0x4419_0b0d,
    0x40d8_16ba,
    0xaca5_c697,
    0xa864_db20,
    0xa527_fdf9,
    0xa1e6_e04e,
    0xbfa1_b04b,
    0xbb60_adfc,
    0xb623_8b25,
    0xb2e2_9692,
    0x8aad_2b2f,
    0x8e6c_3698,
    0x832f_1041,
    0x87ee_0df6,
    0x99a9_5df3,
    0x9d68_4044,
    0x902b_669d,
    0x94ea_7b2a,
    0xe0b4_1de7,
    0xe475_0050,
    0xe936_2689,
    0xedf7_3b3e,
    0xf3b0_6b3b,
    0xf771_768c,
    0xfa32_5055,
    0xfef3_4de2,
    0xc6bc_f05f,
    0xc27d_ede8,
    0xcf3e_cb31,
    0xcbff_d686,
    0xd5b8_8683,
    0xd179_9b34,
    0xdc3a_bded,
    0xd8fb_a05a,
    0x690c_e0ee,
    0x6dcd_fd59,
    0x608e_db80,
    0x644f_c637,
    0x7a08_9632,
    0x7ec9_8b85,
    0x738a_ad5c,
    0x774b_b0eb,
    0x4f04_0d56,
    0x4bc5_10e1,
    0x4686_3638,
    0x4247_2b8f,
    0x5c00_7b8a,
    0x58c1_663d,
    0x5582_40e4,
    0x5143_5d53,
    0x251d_3b9e,
    0x21dc_2629,
    0x2c9f_00f0,
    0x285e_1d47,
    0x3619_4d42,
    0x32d8_50f5,
    0x3f9b_762c,
    0x3b5a_6b9b,
    0x0315_d626,
    0x07d4_cb91,
    0x0a97_ed48,
    0x0e56_f0ff,
    0x1011_a0fa,
    0x14d0_bd4d,
    0x1993_9b94,
    0x1d52_8623,
    0xf12f_560e,
    0xf5ee_4bb9,
    0xf8ad_6d60,
    0xfc6c_70d7,
    0xe22b_20d2,
    0xe6ea_3d65,
    0xeba9_1bbc,
    0xef68_060b,
    0xd727_bbb6,
    0xd3e6_a601,
    0xdea5_80d8,
    0xda64_9d6f,
    0xc423_cd6a,
    0xc0e2_d0dd,
    0xcda1_f604,
    0xc960_ebb3,
    0xbd3e_8d7e,
    0xb9ff_90c9,
    0xb4bc_b610,
    0xb07d_aba7,
    0xae3a_fba2,
    0xaafb_e615,
    0xa7b8_c0cc,
    0xa379_dd7b,
    0x9b36_60c6,
    0x9ff7_7d71,
    0x92b4_5ba8,
    0x9675_461f,
    0x8832_161a,
    0x8cf3_0bad,
    0x81b0_2d74,
    0x8571_30c3,
    0x5d8a_9099,
    0x594b_8d2e,
    0x5408_abf7,
    0x50c9_b640,
    0x4e8e_e645,
    0x4a4f_fbf2,
    0x470c_dd2b,
    0x43cd_c09c,
    0x7b82_7d21,
    0x7f43_6096,
    0x7200_464f,
    0x76c1_5bf8,
    0x6886_0bfd,
    0x6c47_164a,
    0x6104_3093,
    0x65c5_2d24,
    0x119b_4be9,
    0x155a_565e,
    0x1819_7087,
    0x1cd8_6d30,
    0x029f_3d35,
    0x065e_2082,
    0x0b1d_065b,
    0x0fdc_1bec,
    0x3793_a651,
    0x3352_bbe6,
    0x3e11_9d3f,
    0x3ad0_8088,
    0x2497_d08d,
    0x2056_cd3a,
    0x2d15_ebe3,
    0x29d4_f654,
    0xc5a9_2679,
    0xc168_3bce,
    0xcc2b_1d17,
    0xc8ea_00a0,
    0xd6ad_50a5,
    0xd26c_4d12,
    0xdf2f_6bcb,
    0xdbee_767c,
    0xe3a1_cbc1,
    0xe760_d676,
    0xea23_f0af,
    0xeee2_ed18,
    0xf0a5_bd1d,
    0xf464_a0aa,
    0xf927_8673,
    0xfde6_9bc4,
    0x89b8_fd09,
    0x8d79_e0be,
    0x803a_c667,
    0x84fb_dbd0,
    0x9abc_8bd5,
    0x9e7d_9662,
    0x933e_b0bb,
    0x97ff_ad0c,
    0xafb0_10b1,
    0xab71_0d06,
    0xa632_2bdf,
    0xa2f3_3668,
    0xbcb4_666d,
    0xb875_7bda,
    0xb536_5d03,
    0xb1f7_40b4,
];

#[cfg(test)]
mod tests {
    use crc::calc_crc;

    #[test]
    fn crc_rumble_test() {
        let data = include_bytes!("../assets/rumble.replay");
        assert_eq!(calc_crc(&data[..]), 2034487435);
    }

    #[test]
    fn single_byte_test() {
        assert_eq!(calc_crc(&[0xa0]), 0x76cc8c81);
    }
}
<commit_msg>Add comments to crc code<commit_after>/// Calculates the crc-32 for rocket league replays. Not all CRC algorithms are the same. The crc
/// algorithm can be generated with the following parameters (pycrc):
///
/// - Width = 32
/// - Poly = 0x04c11db7
/// - XorIn = 0x10340dfe
/// - ReflectIn = False
/// - XorOut = 0xffffffff
/// - ReflectOut = False
///
/// It may be tempting to optimize this function to use slice by techniques, but I have not be able
/// to achieve this. pycrc disables slice by for non-reflected algorithms, and I couldn't get the
/// reversed model from reveng to pass the tests. I've wasted too much time trying to optimize this
/// function. I thought it would be worthwhile as when one is only interested in parsing a replay's
/// header and checking the crc, the crc computation is 100x more intensive than the header
/// parsing.
///
/// I've even tried to lookup the slice by 8 tables of  `CRCTablesSB8` and
/// `CRCTablesSB8_DEPRECATED` from the unreal engine to glean any information on derivation or
/// usage. No such luck. This has been a teachable moment
pub fn calc_crc(data: &[u8]) -> u32 {
    !data.iter().fold(!0xefcb_f201, |acc, &x| {
        (acc << 8) ^ (TABLE[((u32::from(x)) ^ (acc >> 24)) as usize])
    })
}

/// This is equal to the `CRCTable_Deprecated` found in the unreal project
/// ([link](https://docs.unrealengine.com/latest/INT/API/Runtime/Core/Misc/FCrc/CRCTable_DEPRECATED/index.html)). From the docs:
///
/// > These tables and functions are deprecated because they're using tables and implementations
/// > which give values different from what a user of a typical CRC32 algorithm might expect.
const TABLE: [u32; 256] = [
    0x0000_0000,
    0x04c1_1db7,
    0x0982_3b6e,
    0x0d43_26d9,
    0x1304_76dc,
    0x17c5_6b6b,
    0x1a86_4db2,
    0x1e47_5005,
    0x2608_edb8,
    0x22c9_f00f,
    0x2f8a_d6d6,
    0x2b4b_cb61,
    0x350c_9b64,
    0x31cd_86d3,
    0x3c8e_a00a,
    0x384f_bdbd,
    0x4c11_db70,
    0x48d0_c6c7,
    0x4593_e01e,
    0x4152_fda9,
    0x5f15_adac,
    0x5bd4_b01b,
    0x5697_96c2,
    0x5256_8b75,
    0x6a19_36c8,
    0x6ed8_2b7f,
    0x639b_0da6,
    0x675a_1011,
    0x791d_4014,
    0x7ddc_5da3,
    0x709f_7b7a,
    0x745e_66cd,
    0x9823_b6e0,
    0x9ce2_ab57,
    0x91a1_8d8e,
    0x9560_9039,
    0x8b27_c03c,
    0x8fe6_dd8b,
    0x82a5_fb52,
    0x8664_e6e5,
    0xbe2b_5b58,
    0xbaea_46ef,
    0xb7a9_6036,
    0xb368_7d81,
    0xad2f_2d84,
    0xa9ee_3033,
    0xa4ad_16ea,
    0xa06c_0b5d,
    0xd432_6d90,
    0xd0f3_7027,
    0xddb0_56fe,
    0xd971_4b49,
    0xc736_1b4c,
    0xc3f7_06fb,
    0xceb4_2022,
    0xca75_3d95,
    0xf23a_8028,
    0xf6fb_9d9f,
    0xfbb8_bb46,
    0xff79_a6f1,
    0xe13e_f6f4,
    0xe5ff_eb43,
    0xe8bc_cd9a,
    0xec7d_d02d,
    0x3486_7077,
    0x3047_6dc0,
    0x3d04_4b19,
    0x39c5_56ae,
    0x2782_06ab,
    0x2343_1b1c,
    0x2e00_3dc5,
    0x2ac1_2072,
    0x128e_9dcf,
    0x164f_8078,
    0x1b0c_a6a1,
    0x1fcd_bb16,
    0x018a_eb13,
    0x054b_f6a4,
    0x0808_d07d,
    0x0cc9_cdca,
    0x7897_ab07,
    0x7c56_b6b0,
    0x7115_9069,
    0x75d4_8dde,
    0x6b93_dddb,
    0x6f52_c06c,
    0x6211_e6b5,
    0x66d0_fb02,
    0x5e9f_46bf,
    0x5a5e_5b08,
    0x571d_7dd1,
    0x53dc_6066,
    0x4d9b_3063,
    0x495a_2dd4,
    0x4419_0b0d,
    0x40d8_16ba,
    0xaca5_c697,
    0xa864_db20,
    0xa527_fdf9,
    0xa1e6_e04e,
    0xbfa1_b04b,
    0xbb60_adfc,
    0xb623_8b25,
    0xb2e2_9692,
    0x8aad_2b2f,
    0x8e6c_3698,
    0x832f_1041,
    0x87ee_0df6,
    0x99a9_5df3,
    0x9d68_4044,
    0x902b_669d,
    0x94ea_7b2a,
    0xe0b4_1de7,
    0xe475_0050,
    0xe936_2689,
    0xedf7_3b3e,
    0xf3b0_6b3b,
    0xf771_768c,
    0xfa32_5055,
    0xfef3_4de2,
    0xc6bc_f05f,
    0xc27d_ede8,
    0xcf3e_cb31,
    0xcbff_d686,
    0xd5b8_8683,
    0xd179_9b34,
    0xdc3a_bded,
    0xd8fb_a05a,
    0x690c_e0ee,
    0x6dcd_fd59,
    0x608e_db80,
    0x644f_c637,
    0x7a08_9632,
    0x7ec9_8b85,
    0x738a_ad5c,
    0x774b_b0eb,
    0x4f04_0d56,
    0x4bc5_10e1,
    0x4686_3638,
    0x4247_2b8f,
    0x5c00_7b8a,
    0x58c1_663d,
    0x5582_40e4,
    0x5143_5d53,
    0x251d_3b9e,
    0x21dc_2629,
    0x2c9f_00f0,
    0x285e_1d47,
    0x3619_4d42,
    0x32d8_50f5,
    0x3f9b_762c,
    0x3b5a_6b9b,
    0x0315_d626,
    0x07d4_cb91,
    0x0a97_ed48,
    0x0e56_f0ff,
    0x1011_a0fa,
    0x14d0_bd4d,
    0x1993_9b94,
    0x1d52_8623,
    0xf12f_560e,
    0xf5ee_4bb9,
    0xf8ad_6d60,
    0xfc6c_70d7,
    0xe22b_20d2,
    0xe6ea_3d65,
    0xeba9_1bbc,
    0xef68_060b,
    0xd727_bbb6,
    0xd3e6_a601,
    0xdea5_80d8,
    0xda64_9d6f,
    0xc423_cd6a,
    0xc0e2_d0dd,
    0xcda1_f604,
    0xc960_ebb3,
    0xbd3e_8d7e,
    0xb9ff_90c9,
    0xb4bc_b610,
    0xb07d_aba7,
    0xae3a_fba2,
    0xaafb_e615,
    0xa7b8_c0cc,
    0xa379_dd7b,
    0x9b36_60c6,
    0x9ff7_7d71,
    0x92b4_5ba8,
    0x9675_461f,
    0x8832_161a,
    0x8cf3_0bad,
    0x81b0_2d74,
    0x8571_30c3,
    0x5d8a_9099,
    0x594b_8d2e,
    0x5408_abf7,
    0x50c9_b640,
    0x4e8e_e645,
    0x4a4f_fbf2,
    0x470c_dd2b,
    0x43cd_c09c,
    0x7b82_7d21,
    0x7f43_6096,
    0x7200_464f,
    0x76c1_5bf8,
    0x6886_0bfd,
    0x6c47_164a,
    0x6104_3093,
    0x65c5_2d24,
    0x119b_4be9,
    0x155a_565e,
    0x1819_7087,
    0x1cd8_6d30,
    0x029f_3d35,
    0x065e_2082,
    0x0b1d_065b,
    0x0fdc_1bec,
    0x3793_a651,
    0x3352_bbe6,
    0x3e11_9d3f,
    0x3ad0_8088,
    0x2497_d08d,
    0x2056_cd3a,
    0x2d15_ebe3,
    0x29d4_f654,
    0xc5a9_2679,
    0xc168_3bce,
    0xcc2b_1d17,
    0xc8ea_00a0,
    0xd6ad_50a5,
    0xd26c_4d12,
    0xdf2f_6bcb,
    0xdbee_767c,
    0xe3a1_cbc1,
    0xe760_d676,
    0xea23_f0af,
    0xeee2_ed18,
    0xf0a5_bd1d,
    0xf464_a0aa,
    0xf927_8673,
    0xfde6_9bc4,
    0x89b8_fd09,
    0x8d79_e0be,
    0x803a_c667,
    0x84fb_dbd0,
    0x9abc_8bd5,
    0x9e7d_9662,
    0x933e_b0bb,
    0x97ff_ad0c,
    0xafb0_10b1,
    0xab71_0d06,
    0xa632_2bdf,
    0xa2f3_3668,
    0xbcb4_666d,
    0xb875_7bda,
    0xb536_5d03,
    0xb1f7_40b4,
];

#[cfg(test)]
mod tests {
    use crc::calc_crc;

    #[test]
    fn crc_rumble_test() {
        let data = include_bytes!("../assets/rumble.replay");
        assert_eq!(calc_crc(&data[..]), 2034487435);
    }

    #[test]
    fn single_byte_test() {
        assert_eq!(calc_crc(&[0xa0]), 0x76cc8c81);
    }
}
<|endoftext|>


<commit_before>//! Shared interrupt description and set-up code.
//! See the `bits*::irq` modules for arch-specific portions.

use core::fmt;

/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
#[derive(Debug)]
pub struct InterruptDescription {
    pub vector: u8,
    pub mnemonic: &'static str,
    pub description: &'static str,
    pub irqtype: &'static str,
    pub source: &'static str,
}

impl fmt::Display for InterruptDescription {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{} ({}, vec={}) {}",
            self.mnemonic, self.irqtype, self.vector, self.description
        )
    }
}

/// x86 External Interrupts (1-16).
pub static EXCEPTIONS: [InterruptDescription; 21] = [
    InterruptDescription {
        vector: 0,
        mnemonic: "#DE",
        description: "Divide Error",
        irqtype: "Fault",
        source: "DIV and IDIV instructions.",
    },
    InterruptDescription {
        vector: 1,
        mnemonic: "#DB",
        description: "Debug",
        irqtype: "Fault/ Trap",
        source: "Debug condition",
    },
    InterruptDescription {
        vector: 2,
        mnemonic: "NMI",
        description: "Nonmaskable Interrupt",
        irqtype: "Interrupt",
        source: "Nonmaskable external interrupt.",
    },
    InterruptDescription {
        vector: 3,
        mnemonic: "#BP",
        description: "Breakpoint",
        irqtype: "Trap",
        source: "INT 3 instruction.",
    },
    InterruptDescription {
        vector: 4,
        mnemonic: "#OF",
        description: "Overflow",
        irqtype: "Trap",
        source: "INTO instruction.",
    },
    InterruptDescription {
        vector: 5,
        mnemonic: "#BR",
        description: "BOUND Range Exceeded",
        irqtype: "Fault",
        source: "BOUND instruction.",
    },
    InterruptDescription {
        vector: 6,
        mnemonic: "#UD",
        description: "Invalid Opcode (Undefined \
                      Opcode)",
        irqtype: "Fault",
        source: "UD2 instruction or reserved \
                 opcode.",
    },
    InterruptDescription {
        vector: 7,
        mnemonic: "#NM",
        description: "Device Not Available (No \
                      Math Coprocessor)",
        irqtype: "Fault",
        source: "Floating-point or WAIT/FWAIT \
                 instruction.",
    },
    InterruptDescription {
        vector: 8,
        mnemonic: "#DF",
        description: "Double Fault",
        irqtype: "Abort",
        source: "Any instruction that can \
                 generate an exception, an NMI, \
                 or an INTR.",
    },
    InterruptDescription {
        vector: 9,
        mnemonic: "",
        description: "Coprocessor Segment Overrun",
        irqtype: "Fault",
        source: "Floating-point instruction.",
    },
    InterruptDescription {
        vector: 10,
        mnemonic: "#TS",
        description: "Invalid TSS",
        irqtype: "Fault",
        source: "Task switch or TSS access.",
    },
    InterruptDescription {
        vector: 11,
        mnemonic: "#NP",
        description: "Segment Not Present",
        irqtype: "Fault",
        source: "Loading segment registers or \
                 accessing system segments.",
    },
    InterruptDescription {
        vector: 12,
        mnemonic: "#SS",
        description: "Stack-Segment Fault",
        irqtype: "Fault",
        source: "Stack operations and SS register \
                 loads.",
    },
    InterruptDescription {
        vector: 13,
        mnemonic: "#GP",
        description: "General Protection",
        irqtype: "Fault",
        source: "Any memory reference and other \
                 protection checks.",
    },
    InterruptDescription {
        vector: 14,
        mnemonic: "#PF",
        description: "Page Fault",
        irqtype: "Fault",
        source: "Any memory reference.",
    },
    InterruptDescription {
        vector: 15,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "None.",
    },
    InterruptDescription {
        vector: 16,
        mnemonic: "#MF",
        description: "x87 FPU Floating-Point",
        irqtype: "Fault",
        source: "x87 FPU instructions.",
    },
    InterruptDescription {
        vector: 17,
        mnemonic: "#AC",
        description: "Alignment Check",
        irqtype: "Fault",
        source: "Unaligned memory access.",
    },
    InterruptDescription {
        vector: 18,
        mnemonic: "#MC",
        description: "Machine Check",
        irqtype: "Abort",
        source: "Internal machine error.",
    },
    InterruptDescription {
        vector: 19,
        mnemonic: "#XM",
        description: "SIMD Floating-Point",
        irqtype: "Fault",
        source: "SSE SIMD instructions.",
    },
    InterruptDescription {
        vector: 20,
        mnemonic: "#VE",
        description: "Virtualization",
        irqtype: "Fault",
        source: "EPT violation.",
    },
];

bitflags!{
    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
    pub struct PageFaultError: u32 {
        /// 0: The fault was caused by a non-present page.
        /// 1: The fault was caused by a page-level protection violation
        const PFAULT_ERROR_P = bit!(0);

        /// 0: The access causing the fault was a read.
        /// 1: The access causing the fault was a write.
        const PFAULT_ERROR_WR = bit!(1);

        /// 0: The access causing the fault originated when the processor
        /// was executing in supervisor mode.
        /// 1: The access causing the fault originated when the processor
        /// was executing in user mode.
        const PFAULT_ERROR_US = bit!(2);

        /// 0: The fault was not caused by reserved bit violation.
        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
        const PFAULT_ERROR_RSVD = bit!(3);

        /// 0: The fault was not caused by an instruction fetch.
        /// 1: The fault was caused by an instruction fetch.
        const PFAULT_ERROR_ID = bit!(4);

        /// 0: The fault was not by protection keys.
        /// 1: There was a protection key violation.
        const PFAULT_ERROR_PK = bit!(5);
    }
}

impl fmt::Display for PageFaultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.contains(PageFaultError::PFAULT_ERROR_P) {
            false => "The fault was caused by a non-present page.",
            true => "The fault was caused by a page-level protection violation.",
        };
        let wr = match self.contains(PageFaultError::PFAULT_ERROR_WR) {
            false => "The access causing the fault was a read.",
            true => "The access causing the fault was a write.",
        };
        let us = match self.contains(PageFaultError::PFAULT_ERROR_US) {
            false => {
                "The access causing the fault originated when the processor was executing in \
                 supervisor mode."
            }
            true => {
                "The access causing the fault originated when the processor was executing in user \
                 mode."
            }
        };
        let rsvd = match self.contains(PageFaultError::PFAULT_ERROR_RSVD) {
            false => "The fault was not caused by reserved bit violation.",
            true => "The fault was caused by reserved bits set to 1 in a page directory.",
        };
        let id = match self.contains(PageFaultError::PFAULT_ERROR_ID) {
            false => "The fault was not caused by an instruction fetch.",
            true => "The fault was caused by an instruction fetch.",
        };

        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
    }
}

#[test]
fn bit_macro() {
    assert!(PageFaultError::PFAULT_ERROR_PK.bits() == 0b100000);
    assert!(PageFaultError::PFAULT_ERROR_ID.bits() == 0b10000);
    assert!(PageFaultError::PFAULT_ERROR_RSVD.bits() == 0b1000);
    assert!(PageFaultError::PFAULT_ERROR_US.bits() == 0b100);
    assert!(PageFaultError::PFAULT_ERROR_WR.bits() == 0b10);
    assert!(PageFaultError::PFAULT_ERROR_P.bits() == 0b1);
}

/// Enable Interrupts.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ($x:expr) => {{
        asm!("int $0" :: "N" ($x));
    }};
}
<commit_msg>Namespace changes for new bitflags format.<commit_after>//! Shared interrupt description and set-up code.
//! See the `bits*::irq` modules for arch-specific portions.

use core::fmt;

/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
#[derive(Debug)]
pub struct InterruptDescription {
    pub vector: u8,
    pub mnemonic: &'static str,
    pub description: &'static str,
    pub irqtype: &'static str,
    pub source: &'static str,
}

impl fmt::Display for InterruptDescription {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{} ({}, vec={}) {}",
            self.mnemonic, self.irqtype, self.vector, self.description
        )
    }
}

/// x86 External Interrupts (1-16).
pub static EXCEPTIONS: [InterruptDescription; 21] = [
    InterruptDescription {
        vector: 0,
        mnemonic: "#DE",
        description: "Divide Error",
        irqtype: "Fault",
        source: "DIV and IDIV instructions.",
    },
    InterruptDescription {
        vector: 1,
        mnemonic: "#DB",
        description: "Debug",
        irqtype: "Fault/ Trap",
        source: "Debug condition",
    },
    InterruptDescription {
        vector: 2,
        mnemonic: "NMI",
        description: "Nonmaskable Interrupt",
        irqtype: "Interrupt",
        source: "Nonmaskable external interrupt.",
    },
    InterruptDescription {
        vector: 3,
        mnemonic: "#BP",
        description: "Breakpoint",
        irqtype: "Trap",
        source: "INT 3 instruction.",
    },
    InterruptDescription {
        vector: 4,
        mnemonic: "#OF",
        description: "Overflow",
        irqtype: "Trap",
        source: "INTO instruction.",
    },
    InterruptDescription {
        vector: 5,
        mnemonic: "#BR",
        description: "BOUND Range Exceeded",
        irqtype: "Fault",
        source: "BOUND instruction.",
    },
    InterruptDescription {
        vector: 6,
        mnemonic: "#UD",
        description: "Invalid Opcode (Undefined \
                      Opcode)",
        irqtype: "Fault",
        source: "UD2 instruction or reserved \
                 opcode.",
    },
    InterruptDescription {
        vector: 7,
        mnemonic: "#NM",
        description: "Device Not Available (No \
                      Math Coprocessor)",
        irqtype: "Fault",
        source: "Floating-point or WAIT/FWAIT \
                 instruction.",
    },
    InterruptDescription {
        vector: 8,
        mnemonic: "#DF",
        description: "Double Fault",
        irqtype: "Abort",
        source: "Any instruction that can \
                 generate an exception, an NMI, \
                 or an INTR.",
    },
    InterruptDescription {
        vector: 9,
        mnemonic: "",
        description: "Coprocessor Segment Overrun",
        irqtype: "Fault",
        source: "Floating-point instruction.",
    },
    InterruptDescription {
        vector: 10,
        mnemonic: "#TS",
        description: "Invalid TSS",
        irqtype: "Fault",
        source: "Task switch or TSS access.",
    },
    InterruptDescription {
        vector: 11,
        mnemonic: "#NP",
        description: "Segment Not Present",
        irqtype: "Fault",
        source: "Loading segment registers or \
                 accessing system segments.",
    },
    InterruptDescription {
        vector: 12,
        mnemonic: "#SS",
        description: "Stack-Segment Fault",
        irqtype: "Fault",
        source: "Stack operations and SS register \
                 loads.",
    },
    InterruptDescription {
        vector: 13,
        mnemonic: "#GP",
        description: "General Protection",
        irqtype: "Fault",
        source: "Any memory reference and other \
                 protection checks.",
    },
    InterruptDescription {
        vector: 14,
        mnemonic: "#PF",
        description: "Page Fault",
        irqtype: "Fault",
        source: "Any memory reference.",
    },
    InterruptDescription {
        vector: 15,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "None.",
    },
    InterruptDescription {
        vector: 16,
        mnemonic: "#MF",
        description: "x87 FPU Floating-Point",
        irqtype: "Fault",
        source: "x87 FPU instructions.",
    },
    InterruptDescription {
        vector: 17,
        mnemonic: "#AC",
        description: "Alignment Check",
        irqtype: "Fault",
        source: "Unaligned memory access.",
    },
    InterruptDescription {
        vector: 18,
        mnemonic: "#MC",
        description: "Machine Check",
        irqtype: "Abort",
        source: "Internal machine error.",
    },
    InterruptDescription {
        vector: 19,
        mnemonic: "#XM",
        description: "SIMD Floating-Point",
        irqtype: "Fault",
        source: "SSE SIMD instructions.",
    },
    InterruptDescription {
        vector: 20,
        mnemonic: "#VE",
        description: "Virtualization",
        irqtype: "Fault",
        source: "EPT violation.",
    },
];

bitflags!{
    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
    pub struct PageFaultError: u32 {
        /// 0: The fault was caused by a non-present page.
        /// 1: The fault was caused by a page-level protection violation
        const P = bit!(0);

        /// 0: The access causing the fault was a read.
        /// 1: The access causing the fault was a write.
        const WR = bit!(1);

        /// 0: The access causing the fault originated when the processor
        /// was executing in supervisor mode.
        /// 1: The access causing the fault originated when the processor
        /// was executing in user mode.
        const US = bit!(2);

        /// 0: The fault was not caused by reserved bit violation.
        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
        const RSVD = bit!(3);

        /// 0: The fault was not caused by an instruction fetch.
        /// 1: The fault was caused by an instruction fetch.
        const ID = bit!(4);

        /// 0: The fault was not by protection keys.
        /// 1: There was a protection key violation.
        const PK = bit!(5);
    }
}

impl fmt::Display for PageFaultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.contains(PageFaultError::P) {
            false => "The fault was caused by a non-present page.",
            true => "The fault was caused by a page-level protection violation.",
        };
        let wr = match self.contains(PageFaultError::WR) {
            false => "The access causing the fault was a read.",
            true => "The access causing the fault was a write.",
        };
        let us = match self.contains(PageFaultError::US) {
            false => {
                "The access causing the fault originated when the processor was executing in \
                 supervisor mode."
            }
            true => {
                "The access causing the fault originated when the processor was executing in user \
                 mode."
            }
        };
        let rsvd = match self.contains(PageFaultError::RSVD) {
            false => "The fault was not caused by reserved bit violation.",
            true => "The fault was caused by reserved bits set to 1 in a page directory.",
        };
        let id = match self.contains(PageFaultError::ID) {
            false => "The fault was not caused by an instruction fetch.",
            true => "The fault was caused by an instruction fetch.",
        };

        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
    }
}

#[test]
fn bit_macro() {
    assert!(PageFaultError::PK.bits() == 0b100000);
    assert!(PageFaultError::ID.bits() == 0b10000);
    assert!(PageFaultError::RSVD.bits() == 0b1000);
    assert!(PageFaultError::US.bits() == 0b100);
    assert!(PageFaultError::WR.bits() == 0b10);
    assert!(PageFaultError::P.bits() == 0b1);
}

/// Enable Interrupts.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ($x:expr) => {{
        asm!("int $0" :: "N" ($x));
    }};
}
<|endoftext|>


<commit_before>/* Copyright (c) 2014, Peter Nelson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#![crate_name = "jit"]
#![allow(raw_pointer_deriving, dead_code, non_camel_case_types, non_upper_case_globals, unknown_features)]
#![deny(unused_parens, unknown_lints, unreachable_code, unused_allocation, unused_allocation, unused_must_use)]
#![feature(globs, macro_rules, slicing_syntax, unboxed_closures, unsafe_destructor, phase)]
#![stable]
//! This crate wraps LibJIT in an idiomatic style.
//! For example, here's a quick example which makes a multiply function using LibJIT:
//!
//! ```rust
//! extern crate jit;
//! use jit::{Context, get};
//! fn main() {
//!     // make a new context to make functions on
//!     let ref ctx = Context::new();
//!     // get the type of the function
//!     let sig = get::<fn(int, int) -> int>();
//!     // make the function
//!     let func = ctx.build_func(sig, |func| {
//!         let ref x = func[0];
//!         let ref y = func[1];
//!         let ref result = func.insn_mul(x, y);
//!         func.insn_return(result);
//!     });
//!     // compile the IR and get the machine code as a function
//!     let mul = func.with::<(int, int), int>(|mul| {
//!         assert_eq!(mul((4, 5)), 20);
//!     });
//! }
//! ```
extern crate libc;
#[cfg(test)]
extern crate test;
extern crate "libjit-sys" as raw;
use raw::{
    jit_init,
    jit_uses_interpreter,
    jit_supports_threads,
    jit_supports_virtual_memory
};
pub use raw::{
    jit_nint,
    jit_nuint
};
pub use compile::Compile;
pub use context::{Builder, Context};
pub use function::*;
pub use function::flags::CallFlags;
pub use label::Label;
pub use types::kind::TypeKind;
pub use types::*;
pub use util::NativeRef;
pub use value::Value;

/// Initialise the library and prepare for operations
#[inline]
pub fn init() -> () {
    unsafe {
        jit_init()
    }
}
/// Check if the JIT is using a fallback interpreter
#[inline]
pub fn uses_interpreter() -> bool {
    unsafe {
        jit_uses_interpreter() != 0
    }
}
/// Check if the JIT supports theads
#[inline]
pub fn supports_threads() -> bool {
    unsafe {
        jit_supports_threads() != 0
    }
}
/// Check if the JIT supports virtual memory
#[inline]
pub fn supports_virtual_memory() -> bool {
    unsafe {
        jit_supports_virtual_memory() != 0
    }
}
#[macro_escape]
mod macros;
mod context;
mod compile;
mod elf;
mod function;
mod label;
#[cfg(test)]
mod tests;
mod types;
mod util;
mod value;<commit_msg>Export ELF part of library publicly<commit_after>/* Copyright (c) 2014, Peter Nelson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#![crate_name = "jit"]
#![allow(raw_pointer_deriving, dead_code, non_camel_case_types, non_upper_case_globals, unknown_features)]
#![deny(unused_parens, unknown_lints, unreachable_code, unused_allocation, unused_allocation, unused_must_use)]
#![feature(globs, macro_rules, slicing_syntax, unboxed_closures, unsafe_destructor, phase)]
#![stable]
//! This crate wraps LibJIT in an idiomatic style.
//! For example, here's a quick example which makes a multiply function using LibJIT:
//!
//! ```rust
//! extern crate jit;
//! use jit::{Context, get};
//! fn main() {
//!     // make a new context to make functions on
//!     let ref ctx = Context::new();
//!     // get the type of the function
//!     let sig = get::<fn(int, int) -> int>();
//!     // make the function
//!     let func = ctx.build_func(sig, |func| {
//!         let ref x = func[0];
//!         let ref y = func[1];
//!         let ref result = func.insn_mul(x, y);
//!         func.insn_return(result);
//!     });
//!     // compile the IR and get the machine code as a function
//!     let mul = func.with::<(int, int), int>(|mul| {
//!         assert_eq!(mul((4, 5)), 20);
//!     });
//! }
//! ```
extern crate libc;
#[cfg(test)]
extern crate test;
extern crate "libjit-sys" as raw;
use raw::{
    jit_init,
    jit_uses_interpreter,
    jit_supports_threads,
    jit_supports_virtual_memory
};
pub use raw::{
    jit_nint,
    jit_nuint
};
pub use compile::Compile;
pub use context::{Builder, Context};
pub use elf::*;
pub use function::*;
pub use function::flags::CallFlags;
pub use label::Label;
pub use types::kind::TypeKind;
pub use types::*;
pub use util::NativeRef;
pub use value::Value;

/// Initialise the library and prepare for operations
#[inline]
pub fn init() -> () {
    unsafe {
        jit_init()
    }
}
/// Check if the JIT is using a fallback interpreter
#[inline]
pub fn uses_interpreter() -> bool {
    unsafe {
        jit_uses_interpreter() != 0
    }
}
/// Check if the JIT supports theads
#[inline]
pub fn supports_threads() -> bool {
    unsafe {
        jit_supports_threads() != 0
    }
}
/// Check if the JIT supports virtual memory
#[inline]
pub fn supports_virtual_memory() -> bool {
    unsafe {
        jit_supports_virtual_memory() != 0
    }
}
#[macro_escape]
mod macros;
mod context;
mod compile;
mod elf;
mod function;
mod label;
#[cfg(test)]
mod tests;
mod types;
mod util;
mod value;<|endoftext|>


<commit_before>
extern crate cpython;
extern crate numpy;

use numpy::*;

#[test]
fn array_new() {
    let py = cpython::Python::acquire_gil();
    let _arr = PyArray::zeros(py.python(),
                              &[4, 4],
                              NPY_TYPES::NPY_DOUBLE,
                              NPY_ORDER::NPY_CORDER);
}
<commit_msg>Test strides<commit_after>
extern crate cpython;
extern crate numpy;

use numpy::*;

#[test]
fn array_shapes() {
    let py = cpython::Python::acquire_gil();
    let n = 3;
    let m = 5;
    let arr = PyArray::zeros(py.python(),
                             &[n, m],
                             NPY_TYPES::NPY_DOUBLE,
                             NPY_ORDER::NPY_CORDER);
    assert!(arr.ndim() == 2);
    assert!(arr.dims() == [n, m]);
    assert!(arr.strides() == [m as isize * 8, 8]);

    let arr = PyArray::zeros(py.python(),
                             &[n, m],
                             NPY_TYPES::NPY_DOUBLE,
                             NPY_ORDER::NPY_FORTRANORDER);
    assert!(arr.ndim() == 2);
    assert!(arr.dims() == [n, m]);
    assert!(arr.strides() == [8, n as isize * 8]);
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::fmt;
use std::io::prelude::*;
use std::io;
use std::io::{Cursor, ErrorKind, SeekFrom};
use byteorder::{LittleEndian, ReadBytesExt};

#[cfg(feature = "chrono")]
use chrono::{TimeZone, Local};
#[cfg(feature = "chrono")]
use chrono;

use fs::{FileSystemRef, DiskSlice};
use file::File;

#[derive(Clone)]
pub(crate) enum DirRawStream<'a, 'b: 'a> {
    File(File<'a, 'b>),
    Root(DiskSlice<'a, 'b>),
}

impl <'a, 'b> Read for DirRawStream<'a, 'b> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self {
            &mut DirRawStream::File(ref mut file) => file.read(buf),
            &mut DirRawStream::Root(ref mut raw) => raw.read(buf),
        }
    }
}

impl <'a, 'b> Seek for DirRawStream<'a, 'b> {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        match self {
            &mut DirRawStream::File(ref mut file) => file.seek(pos),
            &mut DirRawStream::Root(ref mut raw) => raw.seek(pos),
        }
    }
}

bitflags! {
    #[derive(Default)]
    pub struct FileAttributes: u8 {
        const READ_ONLY  = 0x01;
        const HIDDEN     = 0x02;
        const SYSTEM     = 0x04;
        const VOLUME_ID  = 0x08;
        const DIRECTORY  = 0x10;
        const ARCHIVE    = 0x20;
        const LFN        = Self::READ_ONLY.bits | Self::HIDDEN.bits
                         | Self::SYSTEM.bits | Self::VOLUME_ID.bits;
    }
}

#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
struct DirFileEntryData {
    name: [u8; 11],
    attrs: FileAttributes,
    reserved_0: u8,
    create_time_0: u8,
    create_time_1: u16,
    create_date: u16,
    access_date: u16,
    first_cluster_hi: u16,
    modify_time: u16,
    modify_date: u16,
    first_cluster_lo: u16,
    size: u32,
}

#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
struct DirLfnEntryData {
    order: u8,
    name_0: [u16; 5],
    attrs: FileAttributes,
    entry_type: u8,
    checksum: u8,
    name_1: [u16; 6],
    reserved_0: u16,
    name_2: [u16; 2],
}

#[derive(Clone, Debug)]
enum DirEntryData {
    File(DirFileEntryData),
    Lfn(DirLfnEntryData),
}

#[derive(Clone)]
pub struct DirEntry<'a, 'b: 'a> {
    data: DirFileEntryData,
    lfn: Vec<u16>,
    fs: FileSystemRef<'a, 'b>,
}

#[derive(Clone, Copy, Debug)]
pub struct Date {
    pub year: u16,
    pub month: u16,
    pub day: u16,
}

impl Date {
    pub(crate) fn from_word(dos_date: u16) -> Self {
        let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F);
        Date { year, month, day }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Time {
    pub hour: u16,
    pub min: u16,
    pub sec: u16,
}

impl Time {
    pub(crate) fn from_word(dos_time: u16) -> Self {
        let (hour, min, sec) = (dos_time >> 11, (dos_time >> 5) & 0x3F, (dos_time & 0x1F) * 2);
        Time { hour, min, sec }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct DateTime {
    pub date: Date,
    pub time: Time,
}

impl DateTime {
    pub(crate) fn from_words(dos_date: u16, dos_time: u16) -> Self {
        DateTime {
            date: Date::from_word(dos_date),
            time: Time::from_word(dos_time),
        }
    }
}

#[cfg(feature = "chrono")]
impl From<Date> for chrono::Date<Local> {
    fn from(date: Date) -> Self {
        Local.ymd(date.year as i32, date.month as u32, date.day as u32)
    }
}

#[cfg(feature = "chrono")]
impl From<DateTime> for chrono::DateTime<Local> {
    fn from(date_time: DateTime) -> Self {
        chrono::Date::<Local>::from(date_time.date)
            .and_hms(date_time.time.hour as u32, date_time.time.min as u32, date_time.time.sec as u32)
    }
}

impl <'a, 'b> DirEntry<'a, 'b> {
    pub fn short_file_name(&self) -> String {
        let name_str = String::from_utf8_lossy(&self.data.name[0..8]);
        let ext_str = String::from_utf8_lossy(&self.data.name[8..11]);
        let name_trimmed = name_str.trim_right();
        let ext_trimmed = ext_str.trim_right();
        if ext_trimmed.is_empty() {
            name_trimmed.to_string()
        } else {
            format!("{}.{}", name_trimmed, ext_trimmed)
        }
    }

    pub fn file_name(&self) -> String {
        if self.lfn.len() > 0 {
            String::from_utf16_lossy(&self.lfn)
        } else {
            self.short_file_name()
        }
    }

    pub fn attributes(&self) -> FileAttributes {
        self.data.attrs
    }

    pub fn is_dir(&self) -> bool {
        self.data.attrs.contains(FileAttributes::DIRECTORY)
    }

    pub fn is_file(&self) -> bool {
        !self.is_dir()
    }

    pub(crate) fn first_cluster(&self) -> Option<u32> {
        let n = ((self.data.first_cluster_hi as u32) << 16) | self.data.first_cluster_lo as u32;
        if n == 0 { None } else { Some(n) }
    }

    pub fn to_file(&self) -> File<'a, 'b> {
        if self.is_dir() {
            panic!("This is a directory");
        }
        File::new(self.first_cluster(), Some(self.data.size), self.fs)
    }

    pub fn to_dir(&self) -> Dir<'a, 'b> {
        if !self.is_dir() {
            panic!("This is a file");
        }
        let file = File::new(self.first_cluster(), None, self.fs);
        Dir::new(DirRawStream::File(file), self.fs)
    }

    pub fn len(&self) -> u64 {
        self.data.size as u64
    }

    pub fn created(&self) -> DateTime {
        DateTime::from_words(self.data.create_date, self.data.create_time_1)
    }

    pub fn accessed(&self) -> Date {
        Date::from_word(self.data.access_date)
    }

    pub fn modified(&self) -> DateTime {
        DateTime::from_words(self.data.modify_date, self.data.modify_time)
    }
}

impl <'a, 'b> fmt::Debug for DirEntry<'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.data.fmt(f)
    }
}

#[derive(Clone)]
pub struct Dir<'a, 'b: 'a> {
    rdr: DirRawStream<'a, 'b>,
    fs: FileSystemRef<'a, 'b>,
}

impl <'a, 'b> Dir<'a, 'b> {

    pub(crate) fn new(rdr: DirRawStream<'a, 'b>, fs: FileSystemRef<'a, 'b>) -> Dir<'a, 'b> {
        Dir { rdr, fs }
    }

    pub fn iter(&self) -> DirIter<'a, 'b> {
        DirIter {
            rdr: self.rdr.clone(),
            fs: self.fs.clone(),
            err: false,
        }
    }

    fn split_path<'c>(path: &'c str) -> (&'c str, Option<&'c str>) {
        let mut path_split = path.trim_matches('/').splitn(2, "/");
        let comp = path_split.next().unwrap();
        let rest_opt = path_split.next();
        (comp, rest_opt)
    }

    fn find_entry(&mut self, name: &str) -> io::Result<DirEntry<'a, 'b>> {
        for r in self.iter() {
            let e = r?;
            if e.file_name().eq_ignore_ascii_case(name) {
                return Ok(e);
            }
        }
        Err(io::Error::new(ErrorKind::NotFound, "file not found"))
    }

    pub fn open_dir(&mut self, path: &str) -> io::Result<Dir<'a, 'b>> {
        let (name, rest_opt) = Self::split_path(path);
        let e = self.find_entry(name)?;
        match rest_opt {
            Some(rest) => e.to_dir().open_dir(rest),
            None => Ok(e.to_dir())
        }
    }

    pub fn open_file(&mut self, path: &str) -> io::Result<File<'a, 'b>> {
        let (name, rest_opt) = Self::split_path(path);
        let e = self.find_entry(name)?;
        match rest_opt {
            Some(rest) => e.to_dir().open_file(rest),
            None => Ok(e.to_file())
        }
    }
}

#[derive(Clone)]
pub struct DirIter<'a, 'b: 'a> {
    rdr: DirRawStream<'a, 'b>,
    fs: FileSystemRef<'a, 'b>,
    err: bool,
}

impl <'a, 'b> DirIter<'a, 'b> {
    fn read_dir_entry_data(&mut self) -> io::Result<DirEntryData> {
        let mut name = [0; 11];
        self.rdr.read_exact(&mut name)?;
        let attrs = FileAttributes::from_bits_truncate(self.rdr.read_u8()?);
        if attrs == FileAttributes::LFN {
            let mut data = DirLfnEntryData {
                attrs, ..Default::default()
            };
            let mut cur = Cursor::new(&name);
            data.order = cur.read_u8()?;
            cur.read_u16_into::<LittleEndian>(&mut data.name_0)?;
            data.entry_type = self.rdr.read_u8()?;
            data.checksum = self.rdr.read_u8()?;
            self.rdr.read_u16_into::<LittleEndian>(&mut data.name_1)?;
            data.reserved_0 = self.rdr.read_u16::<LittleEndian>()?;
            self.rdr.read_u16_into::<LittleEndian>(&mut data.name_2)?;
            Ok(DirEntryData::Lfn(data))
        } else {
            let data = DirFileEntryData {
                name,
                attrs,
                reserved_0:       self.rdr.read_u8()?,
                create_time_0:    self.rdr.read_u8()?,
                create_time_1:    self.rdr.read_u16::<LittleEndian>()?,
                create_date:      self.rdr.read_u16::<LittleEndian>()?,
                access_date:      self.rdr.read_u16::<LittleEndian>()?,
                first_cluster_hi: self.rdr.read_u16::<LittleEndian>()?,
                modify_time:      self.rdr.read_u16::<LittleEndian>()?,
                modify_date:      self.rdr.read_u16::<LittleEndian>()?,
                first_cluster_lo: self.rdr.read_u16::<LittleEndian>()?,
                size:             self.rdr.read_u32::<LittleEndian>()?,
            };
            Ok(DirEntryData::File(data))
        }
    }
}

impl <'a, 'b> Iterator for DirIter<'a, 'b> {
    type Item = io::Result<DirEntry<'a, 'b>>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.err {
            return None;
        }
        let mut lfn_buf = Vec::<u16>::new();
        loop {
            let res = self.read_dir_entry_data();
            let data = match res {
                Ok(data) => data,
                Err(err) => {
                    self.err = true;
                    return Some(Err(err));
                },
            };
            match data {
                DirEntryData::File(data) => {
                    // Check if this is end of dif
                    if data.name[0] == 0 {
                        return None;
                    }
                    // Check if this is deleted or volume ID entry
                    if data.name[0] == 0xE5 || data.attrs.contains(FileAttributes::VOLUME_ID) {
                        lfn_buf.clear();
                        continue;
                    }
                    // Truncate 0 and 0xFFFF characters from LFN buffer
                    let mut lfn_len = lfn_buf.len();
                    loop {
                        if lfn_len == 0 {
                            break;
                        }
                        match lfn_buf[lfn_len-1] {
                            0xFFFF | 0 => lfn_len -= 1,
                            _ => break,
                        }
                    }
                    lfn_buf.truncate(lfn_len);
                    return Some(Ok(DirEntry {
                        data,
                        lfn: lfn_buf,
                        fs: self.fs,
                    }));
                },
                DirEntryData::Lfn(data) => {
                    // Check if this is deleted entry
                    if data.order == 0xE5 {
                        lfn_buf.clear();
                        continue;
                    }
                    const LFN_PART_LEN: usize = 13;
                    let index = (data.order & 0x1F) - 1;
                    let pos = LFN_PART_LEN * index as usize;
                    // resize LFN buffer to have enough space for entire name
                    if lfn_buf.len() < pos + LFN_PART_LEN {
                       lfn_buf.resize(pos + LFN_PART_LEN, 0);
                    }
                    // copy name parts into LFN buffer
                    lfn_buf[pos+0..pos+5].clone_from_slice(&data.name_0);
                    lfn_buf[pos+5..pos+11].clone_from_slice(&data.name_1);
                    lfn_buf[pos+11..pos+13].clone_from_slice(&data.name_2);
                }
            };
        }
    }
}
<commit_msg>Fix dir entries pointing to root directory.<commit_after>use std::ascii::AsciiExt;
use std::fmt;
use std::io::prelude::*;
use std::io;
use std::io::{Cursor, ErrorKind, SeekFrom};
use byteorder::{LittleEndian, ReadBytesExt};

#[cfg(feature = "chrono")]
use chrono::{TimeZone, Local};
#[cfg(feature = "chrono")]
use chrono;

use fs::{FileSystemRef, DiskSlice};
use file::File;

#[derive(Clone)]
pub(crate) enum DirRawStream<'a, 'b: 'a> {
    File(File<'a, 'b>),
    Root(DiskSlice<'a, 'b>),
}

impl <'a, 'b> Read for DirRawStream<'a, 'b> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self {
            &mut DirRawStream::File(ref mut file) => file.read(buf),
            &mut DirRawStream::Root(ref mut raw) => raw.read(buf),
        }
    }
}

impl <'a, 'b> Seek for DirRawStream<'a, 'b> {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        match self {
            &mut DirRawStream::File(ref mut file) => file.seek(pos),
            &mut DirRawStream::Root(ref mut raw) => raw.seek(pos),
        }
    }
}

bitflags! {
    #[derive(Default)]
    pub struct FileAttributes: u8 {
        const READ_ONLY  = 0x01;
        const HIDDEN     = 0x02;
        const SYSTEM     = 0x04;
        const VOLUME_ID  = 0x08;
        const DIRECTORY  = 0x10;
        const ARCHIVE    = 0x20;
        const LFN        = Self::READ_ONLY.bits | Self::HIDDEN.bits
                         | Self::SYSTEM.bits | Self::VOLUME_ID.bits;
    }
}

#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
struct DirFileEntryData {
    name: [u8; 11],
    attrs: FileAttributes,
    reserved_0: u8,
    create_time_0: u8,
    create_time_1: u16,
    create_date: u16,
    access_date: u16,
    first_cluster_hi: u16,
    modify_time: u16,
    modify_date: u16,
    first_cluster_lo: u16,
    size: u32,
}

#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
struct DirLfnEntryData {
    order: u8,
    name_0: [u16; 5],
    attrs: FileAttributes,
    entry_type: u8,
    checksum: u8,
    name_1: [u16; 6],
    reserved_0: u16,
    name_2: [u16; 2],
}

#[derive(Clone, Debug)]
enum DirEntryData {
    File(DirFileEntryData),
    Lfn(DirLfnEntryData),
}

#[derive(Clone)]
pub struct DirEntry<'a, 'b: 'a> {
    data: DirFileEntryData,
    lfn: Vec<u16>,
    fs: FileSystemRef<'a, 'b>,
}

#[derive(Clone, Copy, Debug)]
pub struct Date {
    pub year: u16,
    pub month: u16,
    pub day: u16,
}

impl Date {
    pub(crate) fn from_word(dos_date: u16) -> Self {
        let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F);
        Date { year, month, day }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Time {
    pub hour: u16,
    pub min: u16,
    pub sec: u16,
}

impl Time {
    pub(crate) fn from_word(dos_time: u16) -> Self {
        let (hour, min, sec) = (dos_time >> 11, (dos_time >> 5) & 0x3F, (dos_time & 0x1F) * 2);
        Time { hour, min, sec }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct DateTime {
    pub date: Date,
    pub time: Time,
}

impl DateTime {
    pub(crate) fn from_words(dos_date: u16, dos_time: u16) -> Self {
        DateTime {
            date: Date::from_word(dos_date),
            time: Time::from_word(dos_time),
        }
    }
}

#[cfg(feature = "chrono")]
impl From<Date> for chrono::Date<Local> {
    fn from(date: Date) -> Self {
        Local.ymd(date.year as i32, date.month as u32, date.day as u32)
    }
}

#[cfg(feature = "chrono")]
impl From<DateTime> for chrono::DateTime<Local> {
    fn from(date_time: DateTime) -> Self {
        chrono::Date::<Local>::from(date_time.date)
            .and_hms(date_time.time.hour as u32, date_time.time.min as u32, date_time.time.sec as u32)
    }
}

impl <'a, 'b> DirEntry<'a, 'b> {
    pub fn short_file_name(&self) -> String {
        let name_str = String::from_utf8_lossy(&self.data.name[0..8]);
        let ext_str = String::from_utf8_lossy(&self.data.name[8..11]);
        let name_trimmed = name_str.trim_right();
        let ext_trimmed = ext_str.trim_right();
        if ext_trimmed.is_empty() {
            name_trimmed.to_string()
        } else {
            format!("{}.{}", name_trimmed, ext_trimmed)
        }
    }

    pub fn file_name(&self) -> String {
        if self.lfn.len() > 0 {
            String::from_utf16_lossy(&self.lfn)
        } else {
            self.short_file_name()
        }
    }

    pub fn attributes(&self) -> FileAttributes {
        self.data.attrs
    }

    pub fn is_dir(&self) -> bool {
        self.data.attrs.contains(FileAttributes::DIRECTORY)
    }

    pub fn is_file(&self) -> bool {
        !self.is_dir()
    }

    pub(crate) fn first_cluster(&self) -> Option<u32> {
        let n = ((self.data.first_cluster_hi as u32) << 16) | self.data.first_cluster_lo as u32;
        if n == 0 { None } else { Some(n) }
    }

    pub fn to_file(&self) -> File<'a, 'b> {
        assert!(!self.is_dir(), "Not a file entry");
        File::new(self.first_cluster(), Some(self.data.size), self.fs)
    }

    pub fn to_dir(&self) -> Dir<'a, 'b> {
        assert!(self.is_dir(), "Not a directory entry");
        match self.first_cluster() {
            Some(n) => {
                let file = File::new(Some(n), None, self.fs);
                Dir::new(DirRawStream::File(file), self.fs)
            },
            None => self.fs.root_dir(),
        }
    }

    pub fn len(&self) -> u64 {
        self.data.size as u64
    }

    pub fn created(&self) -> DateTime {
        DateTime::from_words(self.data.create_date, self.data.create_time_1)
    }

    pub fn accessed(&self) -> Date {
        Date::from_word(self.data.access_date)
    }

    pub fn modified(&self) -> DateTime {
        DateTime::from_words(self.data.modify_date, self.data.modify_time)
    }
}

impl <'a, 'b> fmt::Debug for DirEntry<'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.data.fmt(f)
    }
}

#[derive(Clone)]
pub struct Dir<'a, 'b: 'a> {
    rdr: DirRawStream<'a, 'b>,
    fs: FileSystemRef<'a, 'b>,
}

impl <'a, 'b> Dir<'a, 'b> {

    pub(crate) fn new(rdr: DirRawStream<'a, 'b>, fs: FileSystemRef<'a, 'b>) -> Dir<'a, 'b> {
        Dir { rdr, fs }
    }

    pub fn iter(&self) -> DirIter<'a, 'b> {
        DirIter {
            rdr: self.rdr.clone(),
            fs: self.fs.clone(),
            err: false,
        }
    }

    fn split_path<'c>(path: &'c str) -> (&'c str, Option<&'c str>) {
        let mut path_split = path.trim_matches('/').splitn(2, "/");
        let comp = path_split.next().unwrap(); // safe unwrap - splitn always returns at least one element
        let rest_opt = path_split.next();
        (comp, rest_opt)
    }

    fn find_entry(&mut self, name: &str) -> io::Result<DirEntry<'a, 'b>> {
        for r in self.iter() {
            let e = r?;
            if e.file_name().eq_ignore_ascii_case(name) {
                return Ok(e);
            }
        }
        Err(io::Error::new(ErrorKind::NotFound, "file not found"))
    }

    pub fn open_dir(&mut self, path: &str) -> io::Result<Dir<'a, 'b>> {
        let (name, rest_opt) = Self::split_path(path);
        let e = self.find_entry(name)?;
        match rest_opt {
            Some(rest) => e.to_dir().open_dir(rest),
            None => Ok(e.to_dir())
        }
    }

    pub fn open_file(&mut self, path: &str) -> io::Result<File<'a, 'b>> {
        let (name, rest_opt) = Self::split_path(path);
        let e = self.find_entry(name)?;
        match rest_opt {
            Some(rest) => e.to_dir().open_file(rest),
            None => Ok(e.to_file())
        }
    }
}

#[derive(Clone)]
pub struct DirIter<'a, 'b: 'a> {
    rdr: DirRawStream<'a, 'b>,
    fs: FileSystemRef<'a, 'b>,
    err: bool,
}

impl <'a, 'b> DirIter<'a, 'b> {
    fn read_dir_entry_data(&mut self) -> io::Result<DirEntryData> {
        let mut name = [0; 11];
        self.rdr.read_exact(&mut name)?;
        let attrs = FileAttributes::from_bits_truncate(self.rdr.read_u8()?);
        if attrs == FileAttributes::LFN {
            let mut data = DirLfnEntryData {
                attrs, ..Default::default()
            };
            let mut cur = Cursor::new(&name);
            data.order = cur.read_u8()?;
            cur.read_u16_into::<LittleEndian>(&mut data.name_0)?;
            data.entry_type = self.rdr.read_u8()?;
            data.checksum = self.rdr.read_u8()?;
            self.rdr.read_u16_into::<LittleEndian>(&mut data.name_1)?;
            data.reserved_0 = self.rdr.read_u16::<LittleEndian>()?;
            self.rdr.read_u16_into::<LittleEndian>(&mut data.name_2)?;
            Ok(DirEntryData::Lfn(data))
        } else {
            let data = DirFileEntryData {
                name,
                attrs,
                reserved_0:       self.rdr.read_u8()?,
                create_time_0:    self.rdr.read_u8()?,
                create_time_1:    self.rdr.read_u16::<LittleEndian>()?,
                create_date:      self.rdr.read_u16::<LittleEndian>()?,
                access_date:      self.rdr.read_u16::<LittleEndian>()?,
                first_cluster_hi: self.rdr.read_u16::<LittleEndian>()?,
                modify_time:      self.rdr.read_u16::<LittleEndian>()?,
                modify_date:      self.rdr.read_u16::<LittleEndian>()?,
                first_cluster_lo: self.rdr.read_u16::<LittleEndian>()?,
                size:             self.rdr.read_u32::<LittleEndian>()?,
            };
            Ok(DirEntryData::File(data))
        }
    }
}

impl <'a, 'b> Iterator for DirIter<'a, 'b> {
    type Item = io::Result<DirEntry<'a, 'b>>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.err {
            return None;
        }
        let mut lfn_buf = Vec::<u16>::new();
        loop {
            let res = self.read_dir_entry_data();
            let data = match res {
                Ok(data) => data,
                Err(err) => {
                    self.err = true;
                    return Some(Err(err));
                },
            };
            match data {
                DirEntryData::File(data) => {
                    // Check if this is end of dif
                    if data.name[0] == 0 {
                        return None;
                    }
                    // Check if this is deleted or volume ID entry
                    if data.name[0] == 0xE5 || data.attrs.contains(FileAttributes::VOLUME_ID) {
                        lfn_buf.clear();
                        continue;
                    }
                    // Truncate 0 and 0xFFFF characters from LFN buffer
                    let mut lfn_len = lfn_buf.len();
                    loop {
                        if lfn_len == 0 {
                            break;
                        }
                        match lfn_buf[lfn_len-1] {
                            0xFFFF | 0 => lfn_len -= 1,
                            _ => break,
                        }
                    }
                    lfn_buf.truncate(lfn_len);
                    return Some(Ok(DirEntry {
                        data,
                        lfn: lfn_buf,
                        fs: self.fs,
                    }));
                },
                DirEntryData::Lfn(data) => {
                    // Check if this is deleted entry
                    if data.order == 0xE5 {
                        lfn_buf.clear();
                        continue;
                    }
                    const LFN_PART_LEN: usize = 13;
                    let index = (data.order & 0x1F) - 1;
                    let pos = LFN_PART_LEN * index as usize;
                    // resize LFN buffer to have enough space for entire name
                    if lfn_buf.len() < pos + LFN_PART_LEN {
                       lfn_buf.resize(pos + LFN_PART_LEN, 0);
                    }
                    // copy name parts into LFN buffer
                    lfn_buf[pos+0..pos+5].clone_from_slice(&data.name_0);
                    lfn_buf[pos+5..pos+11].clone_from_slice(&data.name_1);
                    lfn_buf[pos+11..pos+13].clone_from_slice(&data.name_2);
                }
            };
        }
    }
}
<|endoftext|>