<commit_before>//! Handle `cargo add` arguments

#![allow(clippy::bool_assert_comparison)]

use cargo_edit::{
    find, get_features_from_registry, get_manifest_from_url, registry_url, workspace_members,
    Dependency, LocalManifest,
};
use cargo_edit::{get_latest_dependency, CrateSpec};
use cargo_metadata::Package;
use clap::Parser;
use std::path::PathBuf;

use crate::errors::*;

#[derive(Debug, Parser)]
#[clap(bin_name = "cargo")]
pub enum Command {
    /// Add dependencies to a Cargo.toml manifest file.
    #[clap(name = "add")]
    #[clap(after_help = "\
Examples:
  $ cargo add regex
  $ cargo add regex@0.1.41 --build
  $ cargo add trycmd --dev
  $ cargo add ./crate/parser/
")]
    Add(Args),
}

#[derive(Debug, Parser)]
#[clap(about, version)]
#[clap(setting = clap::AppSettings::DeriveDisplayOrder)]
pub struct Args {
    /// Reference to a package to add as a dependency
    ///
    /// You can reference a packages by:{n}
    /// - `<name>`, like `cargo add serde` (latest version will be used){n}
    /// - `<name>@<version-req>`, like `cargo add serde@1` or `cargo add serde@=1.0.38`{n}
    /// - `<path>`, like `cargo add ./crates/parser/`
    #[clap(value_name = "DEP_ID", required = true)]
    pub crates: Vec<String>,

    /// Disable the default features
    #[clap(long)]
    no_default_features: bool,
    /// Re-enable the default features
    #[clap(long, overrides_with = "no-default-features")]
    default_features: bool,

    /// Space-separated list of features to add
    #[clap(long)]
    pub features: Option<Vec<String>>,

    /// Mark the dependency as optional
    ///
    /// The package name will be exposed as feature of your crate.
    #[clap(long, conflicts_with = "dev")]
    pub optional: bool,

    /// Mark the dependency as required
    ///
    /// The package will be removed from your features.
    #[clap(long, conflicts_with = "dev", overrides_with = "optional")]
    pub no_optional: bool,

    /// Rename the dependency
    ///
    /// Example uses:{n}
    /// - Depending on multiple versions of a crate{n}
    /// - Depend on crates with the same name from different registries
    #[clap(long, short)]
    pub rename: Option<String>,

    /// Package registry for this dependency
    #[clap(long, conflicts_with = "git")]
    pub registry: Option<String>,

    /// Add as development dependency
    ///
    /// Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks.
    ///
    /// These dependencies are not propagated to other packages which depend on this package.
    #[clap(short = 'D', long, help_heading = "SECTION", group = "section")]
    pub dev: bool,

    /// Add as build dependency
    ///
    /// Build-dependencies are the only dependencies available for use by build scripts (`build.rs`
    /// files).
    #[clap(short = 'B', long, help_heading = "SECTION", group = "section")]
    pub build: bool,

    /// Add as dependency to the given target platform.
    #[clap(
        long,
        forbid_empty_values = true,
        help_heading = "SECTION",
        group = "section"
    )]
    pub target: Option<String>,

    /// Path to `Cargo.toml`
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to modify
    #[clap(short = 'p', long = "package", value_name = "PKGID")]
    pub pkgid: Option<String>,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Do not print any output in case of success.
    #[clap(long)]
    pub quiet: bool,

    /// Unstable (nightly-only) flags
    #[clap(
        short = 'Z',
        value_name = "FLAG",
        help_heading = "UNSTABLE",
        global = true,
        arg_enum
    )]
    pub unstable_features: Vec<UnstableOptions>,

    /// Git repository location
    ///
    /// Without any other information, cargo will use latest commit on the main branch.
    #[clap(long, value_name = "URI", help_heading = "UNSTABLE")]
    pub git: Option<String>,

    /// Git branch to download the crate from.
    #[clap(
        long,
        value_name = "BRANCH",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub branch: Option<String>,

    /// Git tag to download the crate from.
    #[clap(
        long,
        value_name = "TAG",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub tag: Option<String>,

    /// Git reference to download the crate from
    ///
    /// This is the catch all, handling hashes to named references in remote repositories.
    #[clap(
        long,
        value_name = "REV",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub rev: Option<String>,
}

impl Args {
    /// Get dependency section
    pub fn get_section(&self) -> Vec<String> {
        if self.dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.build {
            vec!["build-dependencies".to_owned()]
        } else if let Some(ref target) = self.target {
            assert!(!target.is_empty(), "Target specification may not be empty");

            vec![
                "target".to_owned(),
                target.clone(),
                "dependencies".to_owned(),
            ]
        } else {
            vec!["dependencies".to_owned()]
        }
    }

    pub fn default_features(&self) -> Option<bool> {
        resolve_bool_arg(self.default_features, self.no_default_features)
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self, manifest: &LocalManifest) -> Result<Vec<Dependency>> {
        let workspace_members = workspace_members(self.manifest_path.as_deref())?;

        if self.crates.len() > 1 && self.git.is_some() {
            return Err(ErrorKind::MultipleCratesWithGitOrPathOrVers.into());
        }

        if self.crates.len() > 1 && self.rename.is_some() {
            return Err(ErrorKind::MultipleCratesWithRename.into());
        }

        if self.crates.len() > 1 && self.features.is_some() {
            return Err(ErrorKind::MultipleCratesWithFeatures.into());
        }

        self.crates
            .iter()
            .map(|crate_spec| {
                self.parse_single_dependency(manifest, crate_spec, &workspace_members)
            })
            .collect()
    }

    fn parse_single_dependency(
        &self,
        manifest: &LocalManifest,
        crate_spec: &str,
        workspace_members: &[Package],
    ) -> Result<Dependency> {
        let crate_spec = CrateSpec::resolve(crate_spec)?;
        let manifest_path = find(&self.manifest_path)?;
        let registry_url = registry_url(&manifest_path, self.registry.as_deref())?;

        let mut dependency = match &crate_spec {
            CrateSpec::PkgId {
                name: _,
                version_req: Some(_),
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);
                // crate specifier includes a version (e.g. `docopt@0.8`)
                if let Some(ref url) = self.git {
                    let url = url.clone();
                    let version = dependency.version().unwrap().to_string();
                    return Err(ErrorKind::GitUrlWithVersion(url, version).into());
                }

                let features = get_features_from_registry(
                    &dependency.name,
                    dependency
                        .version()
                        .expect("version populated by `parse_as_version`"),
                    &registry_url,
                )?;
                dependency = dependency.set_available_features(features);

                dependency
            }
            CrateSpec::PkgId {
                name,
                version_req: None,
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                if let Some(repo) = &self.git {
                    assert!(self.registry.is_none());
                    let features = get_manifest_from_url(repo)?
                        .map(|m| m.features())
                        .transpose()?
                        .unwrap_or_else(Vec::new);

                    dependency = dependency
                        .set_git(
                            repo,
                            self.branch.clone(),
                            self.tag.clone(),
                            self.rev.clone(),
                        )
                        .set_available_features(features);
                } else if let Some(package) = workspace_members.iter().find(|p| p.name == *name) {
                    // Only special-case workspaces when the user doesn't provide any extra
                    // information, otherwise, trust the user.
                    dependency = dependency.set_path(
                        package
                            .manifest_path
                            .parent()
                            .expect("at least parent dir")
                            .as_std_path()
                            .to_owned(),
                    );
                    // dev-dependencies do not need the version populated
                    if !self.dev {
                        let op = "";
                        let v = format!("{op}{version}", op = op, version = package.version);
                        dependency = dependency.set_version(&v);
                    }
                } else if let Some(version) =
                    manifest.get_dep_version(&self.get_section(), dependency.toml_key())
                {
                    let features =
                        get_features_from_registry(&dependency.name, &version, &registry_url)?;
                    dependency = dependency
                        .set_version(&version)
                        .set_available_features(features);
                } else {
                    let latest =
                        get_latest_dependency(name, false, &manifest_path, Some(&registry_url))?;
                    let op = "";
                    let v = format!(
                        "{op}{version}",
                        op = op,
                        // If version is unavailable `get_latest_dependency` must have
                        // returned `Err(FetchVersionError::GetVersion)`
                        version = latest.version().unwrap_or_else(|| unreachable!())
                    );
                    dependency = dependency
                        .set_version(&v)
                        .set_available_features(latest.available_features);
                }

                dependency
            }
            CrateSpec::Path(_) => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                // dev-dependencies do not need the version populated
                if !self.dev {
                    let dep_path = dependency.path().map(ToOwned::to_owned);
                    if let Some(dep_path) = dep_path {
                        if let Some(package) = workspace_members.iter().find(|p| {
                            p.manifest_path.parent().map(|p| p.as_std_path())
                                == Some(dep_path.as_path())
                        }) {
                            let op = "";
                            let v = format!("{op}{version}", op = op, version = package.version);

                            dependency = dependency.set_version(&v);
                        }
                    }
                }
                dependency
            }
        };

        if let Some(registry) = &self.registry {
            dependency = dependency.set_registry(registry);
        }

        Ok(dependency)
    }

    fn populate_dependency(&self, mut dependency: Dependency) -> Dependency {
        let requested_features: Option<Vec<_>> = self.features.as_ref().map(|v| {
            v.iter()
                .flat_map(|s| s.split(' '))
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(|f| f.to_owned())
                .collect()
        });

        dependency = dependency
            .set_optional(self.optional())
            .set_default_features(self.default_features())
            .set_features(requested_features);

        if let Some(ref rename) = self.rename {
            dependency = dependency.set_rename(rename);
        }

        dependency
    }
}

impl Args {
    pub fn optional(&self) -> Option<bool> {
        resolve_bool_arg(self.optional, self.no_optional)
    }
}

#[cfg(test)]
impl Default for Args {
    fn default() -> Args {
        Args {
            crates: vec!["demo".to_owned()],
            rename: None,
            dev: false,
            build: false,
            git: None,
            branch: None,
            tag: None,
            rev: None,
            target: None,
            optional: false,
            no_optional: false,
            manifest_path: None,
            pkgid: None,
            features: None,
            no_default_features: false,
            default_features: false,
            quiet: false,
            offline: true,
            registry: None,
            unstable_features: vec![],
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
pub enum UnstableOptions {
    Git,
}

fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
    match (yes, no) {
        (true, false) => Some(true),
        (false, true) => Some(false),
        (false, false) => None,
        (_, _) => unreachable!("clap should make this impossible"),
    }
}

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

    #[test]
    fn verify_app() {
        use clap::IntoApp;
        Command::into_app().debug_assert()
    }
}
<commit_msg>refactor(add): Increase precedence of older dep<commit_after>//! Handle `cargo add` arguments

#![allow(clippy::bool_assert_comparison)]

use cargo_edit::{
    find, get_features_from_registry, get_manifest_from_url, registry_url, workspace_members,
    Dependency, LocalManifest,
};
use cargo_edit::{get_latest_dependency, CrateSpec};
use cargo_metadata::Package;
use clap::Parser;
use std::path::PathBuf;

use crate::errors::*;

#[derive(Debug, Parser)]
#[clap(bin_name = "cargo")]
pub enum Command {
    /// Add dependencies to a Cargo.toml manifest file.
    #[clap(name = "add")]
    #[clap(after_help = "\
Examples:
  $ cargo add regex
  $ cargo add regex@0.1.41 --build
  $ cargo add trycmd --dev
  $ cargo add ./crate/parser/
")]
    Add(Args),
}

#[derive(Debug, Parser)]
#[clap(about, version)]
#[clap(setting = clap::AppSettings::DeriveDisplayOrder)]
pub struct Args {
    /// Reference to a package to add as a dependency
    ///
    /// You can reference a packages by:{n}
    /// - `<name>`, like `cargo add serde` (latest version will be used){n}
    /// - `<name>@<version-req>`, like `cargo add serde@1` or `cargo add serde@=1.0.38`{n}
    /// - `<path>`, like `cargo add ./crates/parser/`
    #[clap(value_name = "DEP_ID", required = true)]
    pub crates: Vec<String>,

    /// Disable the default features
    #[clap(long)]
    no_default_features: bool,
    /// Re-enable the default features
    #[clap(long, overrides_with = "no-default-features")]
    default_features: bool,

    /// Space-separated list of features to add
    #[clap(long)]
    pub features: Option<Vec<String>>,

    /// Mark the dependency as optional
    ///
    /// The package name will be exposed as feature of your crate.
    #[clap(long, conflicts_with = "dev")]
    pub optional: bool,

    /// Mark the dependency as required
    ///
    /// The package will be removed from your features.
    #[clap(long, conflicts_with = "dev", overrides_with = "optional")]
    pub no_optional: bool,

    /// Rename the dependency
    ///
    /// Example uses:{n}
    /// - Depending on multiple versions of a crate{n}
    /// - Depend on crates with the same name from different registries
    #[clap(long, short)]
    pub rename: Option<String>,

    /// Package registry for this dependency
    #[clap(long, conflicts_with = "git")]
    pub registry: Option<String>,

    /// Add as development dependency
    ///
    /// Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks.
    ///
    /// These dependencies are not propagated to other packages which depend on this package.
    #[clap(short = 'D', long, help_heading = "SECTION", group = "section")]
    pub dev: bool,

    /// Add as build dependency
    ///
    /// Build-dependencies are the only dependencies available for use by build scripts (`build.rs`
    /// files).
    #[clap(short = 'B', long, help_heading = "SECTION", group = "section")]
    pub build: bool,

    /// Add as dependency to the given target platform.
    #[clap(
        long,
        forbid_empty_values = true,
        help_heading = "SECTION",
        group = "section"
    )]
    pub target: Option<String>,

    /// Path to `Cargo.toml`
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to modify
    #[clap(short = 'p', long = "package", value_name = "PKGID")]
    pub pkgid: Option<String>,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Do not print any output in case of success.
    #[clap(long)]
    pub quiet: bool,

    /// Unstable (nightly-only) flags
    #[clap(
        short = 'Z',
        value_name = "FLAG",
        help_heading = "UNSTABLE",
        global = true,
        arg_enum
    )]
    pub unstable_features: Vec<UnstableOptions>,

    /// Git repository location
    ///
    /// Without any other information, cargo will use latest commit on the main branch.
    #[clap(long, value_name = "URI", help_heading = "UNSTABLE")]
    pub git: Option<String>,

    /// Git branch to download the crate from.
    #[clap(
        long,
        value_name = "BRANCH",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub branch: Option<String>,

    /// Git tag to download the crate from.
    #[clap(
        long,
        value_name = "TAG",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub tag: Option<String>,

    /// Git reference to download the crate from
    ///
    /// This is the catch all, handling hashes to named references in remote repositories.
    #[clap(
        long,
        value_name = "REV",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub rev: Option<String>,
}

impl Args {
    /// Get dependency section
    pub fn get_section(&self) -> Vec<String> {
        if self.dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.build {
            vec!["build-dependencies".to_owned()]
        } else if let Some(ref target) = self.target {
            assert!(!target.is_empty(), "Target specification may not be empty");

            vec![
                "target".to_owned(),
                target.clone(),
                "dependencies".to_owned(),
            ]
        } else {
            vec!["dependencies".to_owned()]
        }
    }

    pub fn default_features(&self) -> Option<bool> {
        resolve_bool_arg(self.default_features, self.no_default_features)
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self, manifest: &LocalManifest) -> Result<Vec<Dependency>> {
        let workspace_members = workspace_members(self.manifest_path.as_deref())?;

        if self.crates.len() > 1 && self.git.is_some() {
            return Err(ErrorKind::MultipleCratesWithGitOrPathOrVers.into());
        }

        if self.crates.len() > 1 && self.rename.is_some() {
            return Err(ErrorKind::MultipleCratesWithRename.into());
        }

        if self.crates.len() > 1 && self.features.is_some() {
            return Err(ErrorKind::MultipleCratesWithFeatures.into());
        }

        self.crates
            .iter()
            .map(|crate_spec| {
                self.parse_single_dependency(manifest, crate_spec, &workspace_members)
            })
            .collect()
    }

    fn parse_single_dependency(
        &self,
        manifest: &LocalManifest,
        crate_spec: &str,
        workspace_members: &[Package],
    ) -> Result<Dependency> {
        let crate_spec = CrateSpec::resolve(crate_spec)?;
        let manifest_path = find(&self.manifest_path)?;
        let registry_url = registry_url(&manifest_path, self.registry.as_deref())?;

        let mut dependency = match &crate_spec {
            CrateSpec::PkgId {
                name: _,
                version_req: Some(_),
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);
                // crate specifier includes a version (e.g. `docopt@0.8`)
                if let Some(ref url) = self.git {
                    let url = url.clone();
                    let version = dependency.version().unwrap().to_string();
                    return Err(ErrorKind::GitUrlWithVersion(url, version).into());
                }

                let features = get_features_from_registry(
                    &dependency.name,
                    dependency
                        .version()
                        .expect("version populated by `parse_as_version`"),
                    &registry_url,
                )?;
                dependency = dependency.set_available_features(features);

                dependency
            }
            CrateSpec::PkgId {
                name,
                version_req: None,
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                if let Some(repo) = &self.git {
                    assert!(self.registry.is_none());
                    let features = get_manifest_from_url(repo)?
                        .map(|m| m.features())
                        .transpose()?
                        .unwrap_or_else(Vec::new);

                    dependency = dependency
                        .set_git(
                            repo,
                            self.branch.clone(),
                            self.tag.clone(),
                            self.rev.clone(),
                        )
                        .set_available_features(features);
                } else if let Some(version) =
                    manifest.get_dep_version(&self.get_section(), dependency.toml_key())
                {
                    let features =
                        get_features_from_registry(&dependency.name, &version, &registry_url)?;
                    dependency = dependency
                        .set_version(&version)
                        .set_available_features(features);
                } else if let Some(package) = workspace_members.iter().find(|p| p.name == *name) {
                    // Only special-case workspaces when the user doesn't provide any extra
                    // information, otherwise, trust the user.
                    dependency = dependency.set_path(
                        package
                            .manifest_path
                            .parent()
                            .expect("at least parent dir")
                            .as_std_path()
                            .to_owned(),
                    );
                    // dev-dependencies do not need the version populated
                    if !self.dev {
                        let op = "";
                        let v = format!("{op}{version}", op = op, version = package.version);
                        dependency = dependency.set_version(&v);
                    }
                } else {
                    let latest =
                        get_latest_dependency(name, false, &manifest_path, Some(&registry_url))?;
                    let op = "";
                    let v = format!(
                        "{op}{version}",
                        op = op,
                        // If version is unavailable `get_latest_dependency` must have
                        // returned `Err(FetchVersionError::GetVersion)`
                        version = latest.version().unwrap_or_else(|| unreachable!())
                    );
                    dependency = dependency
                        .set_version(&v)
                        .set_available_features(latest.available_features);
                }

                dependency
            }
            CrateSpec::Path(_) => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                // dev-dependencies do not need the version populated
                if !self.dev {
                    let dep_path = dependency.path().map(ToOwned::to_owned);
                    if let Some(dep_path) = dep_path {
                        if let Some(package) = workspace_members.iter().find(|p| {
                            p.manifest_path.parent().map(|p| p.as_std_path())
                                == Some(dep_path.as_path())
                        }) {
                            let op = "";
                            let v = format!("{op}{version}", op = op, version = package.version);

                            dependency = dependency.set_version(&v);
                        }
                    }
                }
                dependency
            }
        };

        if let Some(registry) = &self.registry {
            dependency = dependency.set_registry(registry);
        }

        Ok(dependency)
    }

    fn populate_dependency(&self, mut dependency: Dependency) -> Dependency {
        let requested_features: Option<Vec<_>> = self.features.as_ref().map(|v| {
            v.iter()
                .flat_map(|s| s.split(' '))
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(|f| f.to_owned())
                .collect()
        });

        dependency = dependency
            .set_optional(self.optional())
            .set_default_features(self.default_features())
            .set_features(requested_features);

        if let Some(ref rename) = self.rename {
            dependency = dependency.set_rename(rename);
        }

        dependency
    }
}

impl Args {
    pub fn optional(&self) -> Option<bool> {
        resolve_bool_arg(self.optional, self.no_optional)
    }
}

#[cfg(test)]
impl Default for Args {
    fn default() -> Args {
        Args {
            crates: vec!["demo".to_owned()],
            rename: None,
            dev: false,
            build: false,
            git: None,
            branch: None,
            tag: None,
            rev: None,
            target: None,
            optional: false,
            no_optional: false,
            manifest_path: None,
            pkgid: None,
            features: None,
            no_default_features: false,
            default_features: false,
            quiet: false,
            offline: true,
            registry: None,
            unstable_features: vec![],
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
pub enum UnstableOptions {
    Git,
}

fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
    match (yes, no) {
        (true, false) => Some(true),
        (false, true) => Some(false),
        (false, false) => None,
        (_, _) => unreachable!("clap should make this impossible"),
    }
}

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

    #[test]
    fn verify_app() {
        use clap::IntoApp;
        Command::into_app().debug_assert()
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use super::{ByteBuffer, Driver, Dataset, warp};
use gdal_sys::GDALDataType;
use metadata::Metadata;

#[cfg(feature = "ndarray")]
use ndarray::arr2;

macro_rules! fixture {
    ($name:expr) => (
        Path::new(file!())
            .parent().unwrap()
            .parent().unwrap()
            .parent().unwrap()
            .join("fixtures").as_path()
            .join($name).as_path()
    )
}

#[test]
fn test_open() {
    let dataset = Dataset::open(fixture!("tinymarble.png"));
    assert!(dataset.is_ok());

    let missing_dataset = Dataset::open(fixture!("no_such_file.png"));
    assert!(missing_dataset.is_err());
}

#[test]
fn test_get_raster_size() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let (size_x, size_y) = dataset.size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_block_size() {
    let band_index = 1;
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let (size_x, size_y) = rasterband.block_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 1);
}

#[test]
fn test_get_raster_count() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let count = dataset.count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.projection();
    assert_eq!(projection.chars().take(16).collect::<String>(), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_read_raster() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rv = dataset.read_raster(
        1,
        (20, 30),
        (2, 3),
        (2, 3)
    ).unwrap();
    assert_eq!(rv.size.0, 2);
    assert_eq!(rv.size.1, 3);
    assert_eq!(rv.data, vec!(7, 7, 7, 10, 8, 12));
}

#[test]
fn test_write_raster() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();

    // create a 2x1 raster
    let raster = ByteBuffer{
        size: (2, 1),
        data: vec!(50u8, 20u8)
    };

    // epand it to fill the image (20x10)
    let res = dataset.write_raster(
        1,
        (0, 0),
        (20, 10),
        &raster
    );
    assert!(res.is_ok());

    // read a pixel from the left side
    let left = dataset.read_raster(
        1,
        (5, 5),
        (1, 1),
        (1, 1)
    ).unwrap();
    assert_eq!(left.data[0], 50u8);

    // read a pixel from the right side
    let right = dataset.read_raster(
        1,
        (15, 5),
        (1, 1),
        (1, 1)
    ).unwrap();
    assert_eq!(right.data[0], 20u8);
}

#[test]
fn test_get_dataset_driver() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let driver = dataset.driver();
    assert_eq!(driver.short_name(), "PNG");
    assert_eq!(driver.long_name(), "Portable Network Graphics");
}

#[test]
fn test_get_description() {

    let driver = Driver::get("mem").unwrap();
    assert_eq!(driver.description().unwrap(), "MEM".to_string());
}

#[test]
fn test_get_metadata_item() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let key = "None";
    let domain = "None";
    let meta = dataset.metadata_item(key, domain);
    assert_eq!(meta, None);

    let key = "INTERLEAVE";
    let domain = "IMAGE_STRUCTURE";
    let meta = dataset.metadata_item(key, domain);
    assert_eq!(meta, Some(String::from("PIXEL")));
}

#[test]
fn test_set_metadata_item() {
    let driver = Driver::get("MEM").unwrap();
    let mut dataset = driver.create("", 1, 1, 1).unwrap();

    let key = "Test_Key";
    let domain = "Test_Domain";
    let value = "Test_Value";
    let result = dataset.set_metadata_item(key, value, domain);
    assert!(result.is_ok());

    let result = dataset.metadata_item(key, domain);
    assert_eq!(Some(value.to_owned()), result);
}

#[test]
fn test_create() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 10, 20, 3).unwrap();
    assert_eq!(dataset.size(), (10, 20));
    assert_eq!(dataset.count(), 3);
    assert_eq!(dataset.driver().short_name(), "MEM");
}

#[test]
fn test_create_with_band_type() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create_with_band_type::<f32>("", 10, 20, 3).unwrap();
    assert_eq!(dataset.size(), (10, 20));
    assert_eq!(dataset.count(), 3);
    assert_eq!(dataset.driver().short_name(), "MEM");
    assert_eq!(dataset.band_type(1).unwrap(), GDALDataType::GDT_Float32)
}

#[test]
fn test_create_copy() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let copy = dataset.create_copy(&driver, "").unwrap();
    assert_eq!(copy.size(), (100, 50));
    assert_eq!(copy.count(), 3);
}

#[test]
fn test_geo_transform() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();
    let transform = [0., 1., 0., 0., 0., 1.];
    assert!(dataset.set_geo_transform(&transform).is_ok());
    assert_eq!(dataset.geo_transform().unwrap(), transform);
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = Driver::get("wtf");
    assert!(missing_driver.is_err());

    let ok_driver = Driver::get("GTiff");
    assert!(ok_driver.is_ok());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.short_name(), "GTiff");
    assert_eq!(driver.long_name(), "GeoTIFF");
}

#[test]
fn test_read_raster_as() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rv = dataset.read_raster_as::<u8>(
        1,
        (20, 30),
        (2, 3),
        (2, 3)
    ).unwrap();
    assert_eq!(rv.data, vec!(7, 7, 7, 10, 8, 12));
    assert_eq!(rv.size.0, 2);
    assert_eq!(rv.size.1, 3);
    assert_eq!(dataset.band_type(1).unwrap(), GDALDataType::GDT_Byte);
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_raster_as_array() {
    let band_index = 1;
    let (left, top) = (19, 5);
    let (window_size_x, window_size_y) = (3, 4);
    let (array_size_x, array_size_y) = (3, 4);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let values = dataset.read_as_array::<u8>(
        band_index,
        (left, top),
        (window_size_x, window_size_y),
        (array_size_x, array_size_y)
    ).unwrap();

    let data = arr2(&[[226, 225, 157],
                      [215, 222, 225],
                      [213, 231, 229],
                      [171, 189, 192]]);

    assert_eq!(values, data);
    assert_eq!(dataset.band_type(band_index).unwrap(), GDALDataType::GDT_Byte);
}

#[test]
fn test_read_full_raster_as() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rv = dataset.read_full_raster_as::<u8>(1).unwrap();
    assert_eq!(rv.size.0, 100);
    assert_eq!(rv.size.1, 50);
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_block_as_array() {
    let band_index = 1;
    let block_index = (0, 0);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let result = rasterband.read_block::<u8>(block_index);
    assert!(result.is_ok());
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_block_dimension() {
    let band_index = 1;
    let block = (0, 0);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let array = rasterband.read_block::<u8>(block).unwrap();
    let dimension = (1, 100);
    assert_eq!(array.dim(), dimension);
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_block_last_dimension() {
    let band_index = 1;
    let block = (0, 49);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let array = rasterband.read_block::<u8>(block).unwrap();
    let dimension = (1, 100);
    assert_eq!(array.dim(), dimension);
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_block_data() {
    let band_index = 1;
    let block = (0, 0);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let array = rasterband.read_block::<u8>(block).unwrap();
    assert_eq!(array[[0, 0]], 0);
    assert_eq!(array[[0, 1]], 9);
    assert_eq!(array[[0, 98]], 24);
    assert_eq!(array[[0, 99]], 51);
}

#[test]
fn test_get_band_type() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();
    assert_eq!(dataset.band_type(1).unwrap(), GDALDataType::GDT_Byte);
    assert!(dataset.band_type(2).is_err());
}

#[test]
fn test_get_rasterband() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();
    let rasterband = dataset.rasterband(1);
    assert!(rasterband.is_ok())
}

#[test]
fn test_get_no_data_value() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(1).unwrap();
    let no_data_value = rasterband.no_data_value();
    assert!(no_data_value.is_none());

    // let dataset = Dataset::open(fixture!("bluemarble.tif")).unwrap();
    // let rasterband = dataset.get_rasterband(1).unwrap();
    // let no_data_value = rasterband.get_no_data_value();
    // assert_eq!(no_data_value, Some(0.0));
}

#[test]
fn test_set_no_data_value() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();
    let rasterband = dataset.rasterband(1).unwrap();
    assert_eq!(rasterband.no_data_value(), None);
    assert!(rasterband.set_no_data_value(3.14).is_ok());
    assert_eq!(rasterband.no_data_value(), Some(3.14));
}

#[test]
fn test_get_scale() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(1).unwrap();
    let scale = rasterband.scale();
    assert_eq!(scale, Some(1.0));
}

#[test]
fn test_get_offset() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(1).unwrap();
    let offset = rasterband.offset();
    assert_eq!(offset, Some(0.0));
}

#[test]
fn test_reproject() {
    let driver = Driver::get("MEM").unwrap();
    let size_x = 100;
    let size_y = 50;
    let bands = 3;
    let filename = ""; // Don't need concrete filename because is a file in memory
    let destiny = driver.create(filename, size_x, size_y, bands).unwrap();
    let source = Dataset::open(fixture!("tinybluemarble.tif")).unwrap();

    println!("{:?}", source.geo_transform().expect("Geotransform vector."));

    // c = x-coordinate of the upper-left corner of the upper-left pixel
    // a = width of a pixel
    // b = row rotation (typically zero)
    // f = y-coordinate of the of the upper-left corner of the upper-left pixel
    // d = column rotation (typically zero)
    // e = height of a pixel (typically negative)
    let transform = [0.0, 10.0, 0.0, 0.0, 0.0, -10.0];
    assert!(destiny.set_geo_transform(&transform).is_ok());
    assert!(warp::reproject(&source, &destiny).is_ok());
    println!("{:?}", destiny.geo_transform().expect("Geotransform vector."));
}
<commit_msg>Without reproject test.<commit_after>use std::path::Path;
use super::{ByteBuffer, Driver, Dataset, warp};
use gdal_sys::GDALDataType;
use metadata::Metadata;

#[cfg(feature = "ndarray")]
use ndarray::arr2;

macro_rules! fixture {
    ($name:expr) => (
        Path::new(file!())
            .parent().unwrap()
            .parent().unwrap()
            .parent().unwrap()
            .join("fixtures").as_path()
            .join($name).as_path()
    )
}

#[test]
fn test_open() {
    let dataset = Dataset::open(fixture!("tinymarble.png"));
    assert!(dataset.is_ok());

    let missing_dataset = Dataset::open(fixture!("no_such_file.png"));
    assert!(missing_dataset.is_err());
}

#[test]
fn test_get_raster_size() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let (size_x, size_y) = dataset.size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_block_size() {
    let band_index = 1;
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let (size_x, size_y) = rasterband.block_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 1);
}

#[test]
fn test_get_raster_count() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let count = dataset.count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.projection();
    assert_eq!(projection.chars().take(16).collect::<String>(), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_read_raster() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rv = dataset.read_raster(
        1,
        (20, 30),
        (2, 3),
        (2, 3)
    ).unwrap();
    assert_eq!(rv.size.0, 2);
    assert_eq!(rv.size.1, 3);
    assert_eq!(rv.data, vec!(7, 7, 7, 10, 8, 12));
}

#[test]
fn test_write_raster() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();

    // create a 2x1 raster
    let raster = ByteBuffer{
        size: (2, 1),
        data: vec!(50u8, 20u8)
    };

    // epand it to fill the image (20x10)
    let res = dataset.write_raster(
        1,
        (0, 0),
        (20, 10),
        &raster
    );
    assert!(res.is_ok());

    // read a pixel from the left side
    let left = dataset.read_raster(
        1,
        (5, 5),
        (1, 1),
        (1, 1)
    ).unwrap();
    assert_eq!(left.data[0], 50u8);

    // read a pixel from the right side
    let right = dataset.read_raster(
        1,
        (15, 5),
        (1, 1),
        (1, 1)
    ).unwrap();
    assert_eq!(right.data[0], 20u8);
}

#[test]
fn test_get_dataset_driver() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let driver = dataset.driver();
    assert_eq!(driver.short_name(), "PNG");
    assert_eq!(driver.long_name(), "Portable Network Graphics");
}

#[test]
fn test_get_description() {

    let driver = Driver::get("mem").unwrap();
    assert_eq!(driver.description().unwrap(), "MEM".to_string());
}

#[test]
fn test_get_metadata_item() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let key = "None";
    let domain = "None";
    let meta = dataset.metadata_item(key, domain);
    assert_eq!(meta, None);

    let key = "INTERLEAVE";
    let domain = "IMAGE_STRUCTURE";
    let meta = dataset.metadata_item(key, domain);
    assert_eq!(meta, Some(String::from("PIXEL")));
}

#[test]
fn test_set_metadata_item() {
    let driver = Driver::get("MEM").unwrap();
    let mut dataset = driver.create("", 1, 1, 1).unwrap();

    let key = "Test_Key";
    let domain = "Test_Domain";
    let value = "Test_Value";
    let result = dataset.set_metadata_item(key, value, domain);
    assert!(result.is_ok());

    let result = dataset.metadata_item(key, domain);
    assert_eq!(Some(value.to_owned()), result);
}

#[test]
fn test_create() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 10, 20, 3).unwrap();
    assert_eq!(dataset.size(), (10, 20));
    assert_eq!(dataset.count(), 3);
    assert_eq!(dataset.driver().short_name(), "MEM");
}

#[test]
fn test_create_with_band_type() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create_with_band_type::<f32>("", 10, 20, 3).unwrap();
    assert_eq!(dataset.size(), (10, 20));
    assert_eq!(dataset.count(), 3);
    assert_eq!(dataset.driver().short_name(), "MEM");
    assert_eq!(dataset.band_type(1).unwrap(), GDALDataType::GDT_Float32)
}

#[test]
fn test_create_copy() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let copy = dataset.create_copy(&driver, "").unwrap();
    assert_eq!(copy.size(), (100, 50));
    assert_eq!(copy.count(), 3);
}

#[test]
fn test_geo_transform() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();
    let transform = [0., 1., 0., 0., 0., 1.];
    assert!(dataset.set_geo_transform(&transform).is_ok());
    assert_eq!(dataset.geo_transform().unwrap(), transform);
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = Driver::get("wtf");
    assert!(missing_driver.is_err());

    let ok_driver = Driver::get("GTiff");
    assert!(ok_driver.is_ok());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.short_name(), "GTiff");
    assert_eq!(driver.long_name(), "GeoTIFF");
}

#[test]
fn test_read_raster_as() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rv = dataset.read_raster_as::<u8>(
        1,
        (20, 30),
        (2, 3),
        (2, 3)
    ).unwrap();
    assert_eq!(rv.data, vec!(7, 7, 7, 10, 8, 12));
    assert_eq!(rv.size.0, 2);
    assert_eq!(rv.size.1, 3);
    assert_eq!(dataset.band_type(1).unwrap(), GDALDataType::GDT_Byte);
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_raster_as_array() {
    let band_index = 1;
    let (left, top) = (19, 5);
    let (window_size_x, window_size_y) = (3, 4);
    let (array_size_x, array_size_y) = (3, 4);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let values = dataset.read_as_array::<u8>(
        band_index,
        (left, top),
        (window_size_x, window_size_y),
        (array_size_x, array_size_y)
    ).unwrap();

    let data = arr2(&[[226, 225, 157],
                      [215, 222, 225],
                      [213, 231, 229],
                      [171, 189, 192]]);

    assert_eq!(values, data);
    assert_eq!(dataset.band_type(band_index).unwrap(), GDALDataType::GDT_Byte);
}

#[test]
fn test_read_full_raster_as() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rv = dataset.read_full_raster_as::<u8>(1).unwrap();
    assert_eq!(rv.size.0, 100);
    assert_eq!(rv.size.1, 50);
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_block_as_array() {
    let band_index = 1;
    let block_index = (0, 0);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let result = rasterband.read_block::<u8>(block_index);
    assert!(result.is_ok());
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_block_dimension() {
    let band_index = 1;
    let block = (0, 0);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let array = rasterband.read_block::<u8>(block).unwrap();
    let dimension = (1, 100);
    assert_eq!(array.dim(), dimension);
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_block_last_dimension() {
    let band_index = 1;
    let block = (0, 49);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let array = rasterband.read_block::<u8>(block).unwrap();
    let dimension = (1, 100);
    assert_eq!(array.dim(), dimension);
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_block_data() {
    let band_index = 1;
    let block = (0, 0);
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(band_index).unwrap();
    let array = rasterband.read_block::<u8>(block).unwrap();
    assert_eq!(array[[0, 0]], 0);
    assert_eq!(array[[0, 1]], 9);
    assert_eq!(array[[0, 98]], 24);
    assert_eq!(array[[0, 99]], 51);
}

#[test]
fn test_get_band_type() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();
    assert_eq!(dataset.band_type(1).unwrap(), GDALDataType::GDT_Byte);
    assert!(dataset.band_type(2).is_err());
}

#[test]
fn test_get_rasterband() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();
    let rasterband = dataset.rasterband(1);
    assert!(rasterband.is_ok())
}

#[test]
fn test_get_no_data_value() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(1).unwrap();
    let no_data_value = rasterband.no_data_value();
    assert!(no_data_value.is_none());

    // let dataset = Dataset::open(fixture!("bluemarble.tif")).unwrap();
    // let rasterband = dataset.get_rasterband(1).unwrap();
    // let no_data_value = rasterband.get_no_data_value();
    // assert_eq!(no_data_value, Some(0.0));
}

#[test]
fn test_set_no_data_value() {
    let driver = Driver::get("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();
    let rasterband = dataset.rasterband(1).unwrap();
    assert_eq!(rasterband.no_data_value(), None);
    assert!(rasterband.set_no_data_value(3.14).is_ok());
    assert_eq!(rasterband.no_data_value(), Some(3.14));
}

#[test]
fn test_get_scale() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(1).unwrap();
    let scale = rasterband.scale();
    assert_eq!(scale, Some(1.0));
}

#[test]
fn test_get_offset() {
    let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
    let rasterband = dataset.rasterband(1).unwrap();
    let offset = rasterband.offset();
    assert_eq!(offset, Some(0.0));
}
<|endoftext|>


<commit_before>extern crate libc;

use std::os::raw::c_char;
use libc::size_t;
use libc::strncpy;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert!(true);
    }
}

#[no_mangle]
pub extern fn rnc_add(dst: *mut c_char, dstlen: size_t, num_l: *const c_char, num_r: *const c_char) {
    let x = "II";

    unsafe {
        strncpy(dst, x.as_ptr() as *const i8, dstlen);
    }
}
<commit_msg>First red rust test<commit_after>extern crate libc;

use std::os::raw::c_char;
use libc::size_t;
use libc::strncpy;

#[test]
fn add_i_i() {
    let actual_value = _add("I", "I");

    assert_eq!("II", actual_value);
}

#[no_mangle]
pub extern fn rnc_add(dst: *mut c_char, dstlen: size_t, num_l: *const c_char, num_r: *const c_char) {
    let x = _add("", "");

    unsafe {
        strncpy(dst, x.as_ptr() as *const i8, dstlen);
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_int, size_t, strncpy};
use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;

mod add;
pub use add::add;

mod borrow;
pub use borrow::borrow;

mod cmp;
pub use cmp::cmp;

mod denormalize;
pub use denormalize::denormalize;

mod normalize;
pub use normalize::normalize;

mod sub;
pub use sub::sub;

#[no_mangle]
pub extern fn rnc_add(dst: *mut c_char, dstlen: size_t, raw_l: *const c_char, raw_r: *const c_char) -> c_int {
    let num_l;
    let num_r;

    unsafe {
        num_l = CStr::from_ptr(raw_l).to_str().unwrap();
        num_r = CStr::from_ptr(raw_r).to_str().unwrap();
    }

    match add(num_l, num_r) {
        Ok(sum) => {
            if sum.len() > (dstlen - 1) {
                1
            } else {
                let csum = CString::new(sum).unwrap();
                unsafe {
                    strncpy(dst, csum.as_ptr() as *const i8, dstlen);
                }
                0
            }
        },
        Err(_) => {
            1
        }
    }
}

#[no_mangle]
pub extern fn rnc_sub(dst: *mut c_char, dstlen: size_t, num_l: *const c_char, num_r: *const c_char) -> c_int {
    unsafe {
        match sub(CStr::from_ptr(num_l).to_str().unwrap(), CStr::from_ptr(num_r).to_str().unwrap()) {
            Ok(difference) => {
                //if sum.len() > (dstlen - 1) {
                //1
                //} else {
                let cdiff = CString::new(difference).unwrap();
                strncpy(dst, cdiff.as_ptr() as *const i8, dstlen);
                0
            },
            Err(_) => {
                1
            }
        }
    }
}
<commit_msg>Minimize unsafe blocks in rnc_sub<commit_after>extern crate libc;

use libc::{c_int, size_t, strncpy};
use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;

mod add;
pub use add::add;

mod borrow;
pub use borrow::borrow;

mod cmp;
pub use cmp::cmp;

mod denormalize;
pub use denormalize::denormalize;

mod normalize;
pub use normalize::normalize;

mod sub;
pub use sub::sub;

#[no_mangle]
pub extern fn rnc_add(dst: *mut c_char, dstlen: size_t, raw_l: *const c_char, raw_r: *const c_char) -> c_int {
    let num_l;
    let num_r;

    unsafe {
        num_l = CStr::from_ptr(raw_l).to_str().unwrap();
        num_r = CStr::from_ptr(raw_r).to_str().unwrap();
    }

    match add(num_l, num_r) {
        Ok(sum) => {
            if sum.len() > (dstlen - 1) {
                1
            } else {
                let csum = CString::new(sum).unwrap();
                unsafe {
                    strncpy(dst, csum.as_ptr() as *const i8, dstlen);
                }
                0
            }
        },
        Err(_) => {
            1
        }
    }
}

#[no_mangle]
pub extern fn rnc_sub(dst: *mut c_char, dstlen: size_t, raw_l: *const c_char, raw_r: *const c_char) -> c_int {
    let num_l;
    let num_r;

    unsafe {
        num_l = CStr::from_ptr(raw_l).to_str().unwrap();
        num_r = CStr::from_ptr(raw_r).to_str().unwrap();
    }

    match sub(num_l, num_r) {
        Ok(difference) => {
            //if sum.len() > (dstlen - 1) {
            //1
            //} else {
            let cdiff = CString::new(difference).unwrap();
            unsafe {
                strncpy(dst, cdiff.as_ptr() as *const i8, dstlen);
            }
            0
        },
        Err(_) => {
            1
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use std::fmt::{Display, Formatter};

#[derive(Debug)]
pub enum ReadError {
    Input(std::io::Error),
    Decode(prost::DecodeError),
    Magic(u32),
}

#[derive(Debug)]
pub enum WriteError {
    Output(std::io::Error),
    Encode(prost::EncodeError),
}

impl Display for ReadError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use ReadError::*;

        match *self {
            Input(ref err) => write!(fmt, "input error: {}", err),
            Decode(ref err) => write!(fmt, "proto decoding error: {}", err),
            Magic(magic) => write!(fmt, "invalid magic: {}", magic),
        }
    }
}

impl Display for WriteError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use WriteError::*;

        match *self {
            Output(ref err) => write!(fmt, "output error: {}", err),
            Encode(ref err) => write!(fmt, "proto encoding error: {}", err),
        }
    }
}

impl From<std::io::Error> for ReadError {

    fn from(err: std::io::Error) -> ReadError {
        ReadError::Input(err)
    }
}

impl From<prost::DecodeError> for ReadError {

    fn from(err: prost::DecodeError) -> ReadError {
        ReadError::Decode(err)
    }
}

impl From<std::io::Error> for WriteError {

    fn from(err: std::io::Error) -> WriteError {
        WriteError::Output(err)
    }
}

impl From<prost::EncodeError> for WriteError {

    fn from(err: prost::EncodeError) -> WriteError {
        WriteError::Encode(err)
    }
}
<commit_msg>Implement the error trait for the client errors.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use std::error::{Error};
use std::fmt::{Display, Formatter};

#[derive(Debug)]
pub enum ReadError {
    Input(std::io::Error),
    Decode(prost::DecodeError),
    Magic(u32),
}

#[derive(Debug)]
pub enum WriteError {
    Output(std::io::Error),
    Encode(prost::EncodeError),
}

impl Display for ReadError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use ReadError::*;

        match *self {
            Input(ref err) => write!(fmt, "input error: {}", err),
            Decode(ref err) => write!(fmt, "proto decoding error: {}", err),
            Magic(magic) => write!(fmt, "invalid magic: {}", magic),
        }
    }
}

impl Display for WriteError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use WriteError::*;

        match *self {
            Output(ref err) => write!(fmt, "output error: {}", err),
            Encode(ref err) => write!(fmt, "proto encoding error: {}", err),
        }
    }
}

impl Error for ReadError {

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        use ReadError::*;

        match *self {
            Input(ref err) => Some(err),
            Decode(ref err) => Some(err),
            Magic(_) => None,
        }
    }
}

impl Error for WriteError {

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        use WriteError::*;

        match *self {
            Output(ref err) => Some(err),
            Encode(ref err) => Some(err),
        }
    }
}

impl From<std::io::Error> for ReadError {

    fn from(err: std::io::Error) -> ReadError {
        ReadError::Input(err)
    }
}

impl From<prost::DecodeError> for ReadError {

    fn from(err: prost::DecodeError) -> ReadError {
        ReadError::Decode(err)
    }
}

impl From<std::io::Error> for WriteError {

    fn from(err: std::io::Error) -> WriteError {
        WriteError::Output(err)
    }
}

impl From<prost::EncodeError> for WriteError {

    fn from(err: prost::EncodeError) -> WriteError {
        WriteError::Encode(err)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Vector2f};
use math::cgmath::Zero;
use std::ops::{Add, Index, IndexMut, Mul};
use math::cgmath::prelude::Array;
use std::cmp;

/// A 2-dimensional vector in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialVector {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Zero
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::VectorSpace
// TODO: implement cgmath::InnerSpace
// TODO: implement ops::{ ... }
// TODO: Add `unit_q()` and `unit_r()` (see `Vector2::unit_x()` for reference)
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Vector2.html
//

impl AxialVector {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialVector { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Vector2f {
        Vector2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
}

impl fmt::Debug for AxialVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}

impl Zero for AxialVector {
    fn zero() -> AxialVector {
        AxialVector { q: 0, r: 0 }
    }

    fn is_zero(&self) -> bool {
        self.q == 0 && self.r == 0
    }
}

impl Add<AxialVector> for AxialVector {
    type Output = AxialVector;

    fn add(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r + arg2.r,
            q: self.q + arg2.q,
        }
    }
}

impl Mul<AxialType> for AxialVector {
    type Output = AxialVector;

    fn mul(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r * arg2,
            q: self.q * arg2,
        }
    }
}

impl Array for AxialVector {
    type Element = AxialType;

    fn from_value(value: Self::Element) -> Self {
        AxialVector::new(value, value)
    }

    fn sum(self) -> Self::Element {
        self.q + self.r
    }

    fn product(self) -> Self::Element {
        self.q * self.r
    }

    fn min(self) -> Self::Element {
        cmp::min(self.q, self.r)
    }

    fn max(self) -> Self::Element {
        cmp::max(self.q, self.r)
    }
}

impl Index<usize> for AxialVector {
    type Output = AxialType;

    fn index(&self, index: usize) -> &Self::Output {
        let ret: &AxialType = match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        };
        ret
    }
}

impl IndexMut<usize> for AxialVector {
    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}
<commit_msg>added assigns for add, metricspace, fixed some errors, still WIP<commit_after>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Vector2f};
use math::cgmath::Zero;
use std::ops::{Add, AddAssign, Div, Index, IndexMut, Mul, Neg, Rem, Sub};
use math::cgmath::prelude::{Array, MetricSpace};
use std::cmp;

/// A 2-dimensional vector in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialVector {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Zero
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::VectorSpace
// TODO: implement cgmath::InnerSpace
// TODO: implement ops::{ ... }
// TODO: Add `unit_q()` and `unit_r()` (see `Vector2::unit_x()` for reference)
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Vector2.html
//

impl AxialVector {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialVector { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Vector2f {
        Vector2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
}

impl fmt::Debug for AxialVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}

// ********************* Basic Arithmetic (OPS) *********************

impl Neg for AxialVector {
    type Output = AxialVector;

    fn neg(self) -> Self::Output {
        AxialVector {
            q: -self.q,
            r: -self.r,
        }
    }
}

impl Add<AxialVector> for AxialVector {
    type Output = AxialVector;

    fn add(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r + arg2.r,
            q: self.q + arg2.q,
        }
    }
}

impl AddAssign<AxialVector> for AxialVector {
    fn add_assign(&mut self, arg2: AxialVector) {
        self.r += arg2.r;
        self.q += arg2.q;

    }
}

impl Sub<AxialVector> for AxialVector {
    type Output = AxialVector;

    fn sub(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r - arg2.r,
            q: self.q - arg2.q,
        }
    }
}

impl Mul<AxialType> for AxialVector {
    type Output = AxialVector;

    fn mul(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r * arg2,
            q: self.q * arg2,
        }
    }
}

impl Div<AxialType> for AxialVector {
    type Output = AxialVector;

    fn div(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r / arg2,
            q: self.q / arg2,
        }
    }
}

impl Rem<AxialType> for AxialVector {
    type Output = AxialVector;

    fn rem(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r % arg2,
            q: self.q % arg2,
        }
    }
}

// ************ Metric Space ************

impl MetricSpace for AxialVector {
    type Metric = DefaultFloat;

    fn distance(self, other: AxialVector) -> DefaultFloat {
        (self.distance2(other)).sqrt()
    }

    fn distance2(self, other: AxialVector) -> DefaultFloat {
        ((self.q - other.q).pow(2) + (self.r - other.r).pow(2)) as DefaultFloat
    }
}

// ************** Zero ****************

impl Zero for AxialVector {
    fn zero() -> AxialVector {
        AxialVector { q: 0, r: 0 }
    }

    fn is_zero(&self) -> bool {
        self.q == 0 && self.r == 0
    }
}

// *************** Array & Index *******************

impl Array for AxialVector {
    type Element = AxialType;

    fn from_value(value: Self::Element) -> Self {
        AxialVector::new(value, value)
    }

    fn sum(self) -> Self::Element {
        self.q + self.r
    }

    fn product(self) -> Self::Element {
        self.q * self.r
    }

    fn min(self) -> Self::Element {
        cmp::min(self.q, self.r)
    }

    fn max(self) -> Self::Element {
        cmp::max(self.q, self.r)
    }
}

impl Index<usize> for AxialVector {
    type Output = AxialType;

    fn index(&self, index: usize) -> &Self::Output {
        let ret: &AxialType = match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        };
        ret
    }
}

impl IndexMut<usize> for AxialVector {
    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}
<|endoftext|>


<commit_before>//! Common logic for the consolidation of vectors of monoids.
//!
//! Often we find ourselves with collections of records with associated weights (often
//! integers) where we want to reduce the collection to the point that each record occurs
//! at most once, with the accumulated weights. These methods supply that functionality.

use crate::difference::Monoid;

/// Sorts and consolidates `vec`.
pub fn consolidate<T: Ord, R: Monoid>(vec: &mut Vec<(T, R)>) {
    consolidate_from(vec, 0);
}

/// Sorts and consolidate `vec[offset..]`.
///
/// This method will sort `vec[offset..]` and then consolidate runs with the same first
/// element of a pair by accumulating the second elements of the pairs. Should the final
/// accumulation be zero, the element is discarded.
pub fn consolidate_from<T: Ord, R: Monoid>(vec: &mut Vec<(T, R)>, offset: usize) {
    let length = consolidate_slice(&mut vec[offset..]);
    vec.truncate(offset + length);
}

/// Sorts and consolidates a slice, returning the valid prefix length.
pub fn consolidate_slice<T: Ord, R: Monoid>(slice: &mut [(T, R)]) -> usize {

    // We could do an insertion-sort like initial scan which builds up sorted, consolidated runs.
    // In a world where there are not many results, we may never even need to call in to merge sort.
    if slice.len() > 1 {

        slice.sort_by(|x,y| x.0.cmp(&y.0));

        let mut offset = 0;
        for index in 1 .. slice.len() {

            // The following unsafe block elides various bounds checks, using the reasoning that `offset`
            // is always strictly less than `index` at the beginning of each iteration. This is initially
            // true, and in each iteration `offset` can increase by at most one (whereas `index` always
            // increases by one). As `index` is always in bounds, and `offset` starts at zero, it too is
            // always in bounds.
            //
            // LLVM appears to struggle to optimize out Rust's split_at_mut, which would prove disjointness
            // using run-time tests.
            unsafe {

                // LOOP INVARIANT: offset < index
                let ptr1 = slice.as_mut_ptr().offset(offset as isize);
                let ptr2 = slice.as_mut_ptr().offset(index as isize);

                if (*ptr1).0 == (*ptr2).0 {
                    (*ptr1).1 += &(*ptr2).1;
                }
                else {
                    if !(*ptr1).1.is_zero() {
                        offset += 1;
                    }
                    std::mem::swap(&mut *ptr1, &mut *ptr2);
                }

            }
        }
        if !slice[offset].1.is_zero() {
            offset += 1;
        }

        offset
    }
    else {
        slice.len()
    }
}

/// Sorts and consolidates `vec`.
pub fn consolidate_updates<D: Ord, T: Ord, R: Monoid>(vec: &mut Vec<(D, T, R)>) {
    consolidate_updates_from(vec, 0);
}

/// Sorts and consolidate `vec[offset..]`.
///
/// This method will sort `vec[offset..]` and then consolidate runs with the same first
/// element of a pair by accumulating the second elements of the pairs. Should the final
/// accumulation be zero, the element is discarded.
pub fn consolidate_updates_from<D: Ord, T: Ord, R: Monoid>(vec: &mut Vec<(D, T, R)>, offset: usize) {
    let length = consolidate_updates_slice(&mut vec[offset..]);
    vec.truncate(offset + length);
}

/// Sorts and consolidates a slice, returning the valid prefix length.
pub fn consolidate_updates_slice<D: Ord, T: Ord, R: Monoid>(slice: &mut [(D, T, R)]) -> usize {

    // We could do an insertion-sort like initial scan which builds up sorted, consolidated runs.
    // In a world where there are not many results, we may never even need to call in to merge sort.
    if slice.len() > 1 {

        slice.sort_unstable_by(|x,y| (&x.0, &x.1).cmp(&(&y.0, &y.1)));

        let mut offset = 0;
        for index in 1 .. slice.len() {

            // The following unsafe block elides various bounds checks, using the reasoning that `offset`
            // is always strictly less than `index` at the beginning of each iteration. This is initially
            // true, and in each iteration `offset` can increase by at most one (whereas `index` always
            // increases by one). As `index` is always in bounds, and `offset` starts at zero, it too is
            // always in bounds.
            //
            // LLVM appears to struggle to optimize out Rust's split_at_mut, which would prove disjointness
            // using run-time tests.
            unsafe {

                // LOOP INVARIANT: offset < index
                let ptr1 = slice.as_mut_ptr().offset(offset as isize);
                let ptr2 = slice.as_mut_ptr().offset(index as isize);

                if (*ptr1).0 == (*ptr2).0 && (*ptr1).1 == (*ptr2).1 {
                    (*ptr1).2 += &(*ptr2).2;
                }
                else {
                    if !(*ptr1).2.is_zero() {
                        offset += 1;
                    }
                    std::mem::swap(&mut *ptr1, &mut *ptr2);
                }

            }
        }
        if !slice[offset].2.is_zero() {
            offset += 1;
        }

        offset
    }
    else {
        slice.len()
    }
}
<commit_msg>error in mem::swap<commit_after>//! Common logic for the consolidation of vectors of monoids.
//!
//! Often we find ourselves with collections of records with associated weights (often
//! integers) where we want to reduce the collection to the point that each record occurs
//! at most once, with the accumulated weights. These methods supply that functionality.

use crate::difference::Monoid;

/// Sorts and consolidates `vec`.
pub fn consolidate<T: Ord, R: Monoid>(vec: &mut Vec<(T, R)>) {
    consolidate_from(vec, 0);
}

/// Sorts and consolidate `vec[offset..]`.
///
/// This method will sort `vec[offset..]` and then consolidate runs with the same first
/// element of a pair by accumulating the second elements of the pairs. Should the final
/// accumulation be zero, the element is discarded.
pub fn consolidate_from<T: Ord, R: Monoid>(vec: &mut Vec<(T, R)>, offset: usize) {
    let length = consolidate_slice(&mut vec[offset..]);
    vec.truncate(offset + length);
}

/// Sorts and consolidates a slice, returning the valid prefix length.
pub fn consolidate_slice<T: Ord, R: Monoid>(slice: &mut [(T, R)]) -> usize {

    // We could do an insertion-sort like initial scan which builds up sorted, consolidated runs.
    // In a world where there are not many results, we may never even need to call in to merge sort.
    if slice.len() > 1 {

        slice.sort_by(|x,y| x.0.cmp(&y.0));

        let mut offset = 0;
        for index in 1 .. slice.len() {

            // The following unsafe block elides various bounds checks, using the reasoning that `offset`
            // is always strictly less than `index` at the beginning of each iteration. This is initially
            // true, and in each iteration `offset` can increase by at most one (whereas `index` always
            // increases by one). As `index` is always in bounds, and `offset` starts at zero, it too is
            // always in bounds.
            //
            // LLVM appears to struggle to optimize out Rust's split_at_mut, which would prove disjointness
            // using run-time tests.
            unsafe {

                assert!(offset < index);

                // LOOP INVARIANT: offset < index
                let ptr1 = slice.as_mut_ptr().offset(offset as isize);
                let ptr2 = slice.as_mut_ptr().offset(index as isize);

                if (*ptr1).0 == (*ptr2).0 {
                    (*ptr1).1 += &(*ptr2).1;
                }
                else {
                    if !(*ptr1).1.is_zero() {
                        offset += 1;
                    }
                    let ptr1 = slice.as_mut_ptr().offset(offset as isize);
                    std::mem::swap(&mut *ptr1, &mut *ptr2);
                }

                // if slice[offset].0 == slice[index].0 {
                //     let (lo, hi) = slice.split_at_mut(index);
                //     lo[offset].1 += &hi[0].1;
                // }
                // else {
                //     if slice[offset].1.is_zero() {
                //         offset += 1;
                //     }

                // }

            }
        }
        if !slice[offset].1.is_zero() {
            offset += 1;
        }

        offset
    }
    else {
        slice.len()
    }
}

/// Sorts and consolidates `vec`.
pub fn consolidate_updates<D: Ord, T: Ord, R: Monoid>(vec: &mut Vec<(D, T, R)>) {
    consolidate_updates_from(vec, 0);
}

/// Sorts and consolidate `vec[offset..]`.
///
/// This method will sort `vec[offset..]` and then consolidate runs with the same first
/// element of a pair by accumulating the second elements of the pairs. Should the final
/// accumulation be zero, the element is discarded.
pub fn consolidate_updates_from<D: Ord, T: Ord, R: Monoid>(vec: &mut Vec<(D, T, R)>, offset: usize) {
    let length = consolidate_updates_slice(&mut vec[offset..]);
    vec.truncate(offset + length);
}

/// Sorts and consolidates a slice, returning the valid prefix length.
pub fn consolidate_updates_slice<D: Ord, T: Ord, R: Monoid>(slice: &mut [(D, T, R)]) -> usize {

    // We could do an insertion-sort like initial scan which builds up sorted, consolidated runs.
    // In a world where there are not many results, we may never even need to call in to merge sort.
    if slice.len() > 1 {

        slice.sort_unstable_by(|x,y| (&x.0, &x.1).cmp(&(&y.0, &y.1)));

        let mut offset = 0;
        for index in 1 .. slice.len() {

            // The following unsafe block elides various bounds checks, using the reasoning that `offset`
            // is always strictly less than `index` at the beginning of each iteration. This is initially
            // true, and in each iteration `offset` can increase by at most one (whereas `index` always
            // increases by one). As `index` is always in bounds, and `offset` starts at zero, it too is
            // always in bounds.
            //
            // LLVM appears to struggle to optimize out Rust's split_at_mut, which would prove disjointness
            // using run-time tests.
            unsafe {

                // LOOP INVARIANT: offset < index
                let ptr1 = slice.as_mut_ptr().offset(offset as isize);
                let ptr2 = slice.as_mut_ptr().offset(index as isize);

                if (*ptr1).0 == (*ptr2).0 && (*ptr1).1 == (*ptr2).1 {
                    (*ptr1).2 += &(*ptr2).2;
                }
                else {
                    if !(*ptr1).2.is_zero() {
                        offset += 1;
                    }
                    let ptr1 = slice.as_mut_ptr().offset(offset as isize);
                    std::mem::swap(&mut *ptr1, &mut *ptr2);
                }

            }
        }
        if !slice[offset].2.is_zero() {
            offset += 1;
        }

        offset
    }
    else {
        slice.len()
    }
}
<|endoftext|>


<commit_before>//! This module contains writer-based structs and traits.
//!
//! Because `std::io::Write` is only limited to `std` and not `core`, we provide our own [Writer].

use crate::error::EncodeError;

/// Trait that indicates that a struct can be used as a destination to encode data too. This is used by [Encode]
///
/// [Encode]: ../trait.Encode.html
pub trait Writer {
    /// Write `bytes` to the underlying writer. Exactly `bytes.len()` bytes must be written, or else an error should be returned.
    fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError>;
}

/// A helper struct that implements `Writer` for a `&[u8]` slice.
///
/// ```
/// use bincode::enc::write::{Writer, SliceWriter};
///
/// let destination = &mut [0u8; 100];
/// let mut writer = SliceWriter::new(destination);
/// writer.write(&[1, 2, 3, 4, 5]).unwrap();
///
/// assert_eq!(writer.bytes_written(), 5);
/// assert_eq!(destination[0..6], [1, 2, 3, 4, 5, 0]);
/// ```
pub struct SliceWriter<'storage> {
    slice: &'storage mut [u8],
    idx: usize,
}

impl<'storage> SliceWriter<'storage> {
    /// Create a new instance of `SliceWriter` with the given byte array.
    pub fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> {
        SliceWriter {
            slice: bytes,
            idx: 0,
        }
    }

    /// Return the amount of bytes written so far.
    pub fn bytes_written(&self) -> usize {
        self.idx
    }
}

impl<'storage> Writer for SliceWriter<'storage> {
    fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
        let remaining = &mut self.slice[self.idx..];
        if bytes.len() > remaining.len() {
            return Err(EncodeError::UnexpectedEnd);
        }
        self.idx += bytes.len();
        let write_slice = &mut remaining[..bytes.len()];
        write_slice.copy_from_slice(bytes);
        Ok(())
    }
}
<commit_msg>Optimize performance of slice writing<commit_after>//! This module contains writer-based structs and traits.
//!
//! Because `std::io::Write` is only limited to `std` and not `core`, we provide our own [Writer].

use crate::error::EncodeError;

/// Trait that indicates that a struct can be used as a destination to encode data too. This is used by [Encode]
///
/// [Encode]: ../trait.Encode.html
pub trait Writer {
    /// Write `bytes` to the underlying writer. Exactly `bytes.len()` bytes must be written, or else an error should be returned.
    fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError>;
}

/// A helper struct that implements `Writer` for a `&[u8]` slice.
///
/// ```
/// use bincode::enc::write::{Writer, SliceWriter};
///
/// let destination = &mut [0u8; 100];
/// let mut writer = SliceWriter::new(destination);
/// writer.write(&[1, 2, 3, 4, 5]).unwrap();
///
/// assert_eq!(writer.bytes_written(), 5);
/// assert_eq!(destination[0..6], [1, 2, 3, 4, 5, 0]);
/// ```
pub struct SliceWriter<'storage> {
    slice: &'storage mut [u8],
    original_length: usize,
}

impl<'storage> SliceWriter<'storage> {
    /// Create a new instance of `SliceWriter` with the given byte array.
    pub fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> {
        let original = bytes.len();
        SliceWriter {
            slice: bytes,
            original_length: original,
        }
    }

    /// Return the amount of bytes written so far.
    pub fn bytes_written(&self) -> usize {
        self.original_length - self.slice.len()
    }
}

impl<'storage> Writer for SliceWriter<'storage> {
    #[inline(always)]
    fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
        if bytes.len() > self.slice.len() {
            return Err(EncodeError::UnexpectedEnd);
        }
        let (a, b) = core::mem::replace(&mut self.slice, &mut []).split_at_mut(bytes.len());
        a.copy_from_slice(&bytes[..]);
        self.slice = b;

        Ok(())
    }
}
<|endoftext|>


<commit_before>// This file is part of Twig (ported to Rust).
//
// For the copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Twig Error Handling

use std::fmt::{self, Debug, Display};
use std::error;
use std::any::Any;

#[macro_use]
mod macros;
// use std Error-trait to improve cross-crate compatibility
// don't mix it up with Err(X)

/// Lightweight base functionality for error codes
///
/// Similar to std::error::Error, but _without_ error-chaining.
pub trait ErrorCode: Debug + Display + Any {
    /// A short description of the error code.
    ///
    /// The description should not contain newlines or sentence-ending
    /// punctuation, to facilitate embedding in larger user-facing
    /// strings.
    fn description(&self) -> &str;

    /// Returns generic twig error for this error code.
    /// You must provide the location, where the error occured.
    fn at(self, location: Location) -> Error<Self> where
        Self: Sized
    {
        Error::new(self, location)
    }
}

/// Reference implementation to make examples easier.
impl ErrorCode for &'static str {
    fn description(&self) -> &str { *self }
}

/// Transform ErrorCodes
///
/// It is different to the Into-trait, because we only take references.
pub trait GeneralizeTo<T> {
    fn generalize(&self) -> T;
}

/// Record current state of complex objects
///
/// Implement this trait for complex objects. Make sure, that the Dump::Data type
/// does not contain lifetimes to keep error codes simple. In practice this means
/// cloning all referenced data into the dump.
///
/// For any `X: Dump` you can
///
/// * reference the associated type via `<X as Dump>::Data`
/// * create the dump via `X.dump()`
pub trait Dump {
    type Data: Debug + Display + 'static;

    fn dump(&self) -> Self::Data;
}

/// Generic twig error
///
/// Wrapper around some `ErrorCode` - adds location support and error-chaining.
#[derive(Debug)]
pub struct Error<T>
    where T: ErrorCode
{
    // the exception codes are going to be enums
    // - i.e. Exception<MY_ENUM> implements std::error::Error without any boilerplate
    // to MY_ENUM. Hurray! :-)
    code: T,
    // I decided to call this field `code` instead of `error` to not confuse it with the Error trait
    location: Location,
    // chaining is required by std::error::Error
    cause: Option<Box<error::Error>>,
}

impl<T> Error<T>
    where T: ErrorCode
{
    /// Create a new twig error out of some generic error code.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use] extern crate twig;
    /// # fn main() {
    /// Error::new("my error", loc!()); // shorthand: `err!("my error")`
    /// # }
    /// ```
    pub fn new(code: T, location: Location) -> Error<T> {
        Error {
            code: code,
            location: location,
            cause: None
        }
    }

    /// Return the associated error code.
    #[allow(dead_code)] // only used by tests
    pub fn code(&self) -> &T {
        &self.code
    }

    /// Return the location the error occured.
    pub fn location(&self) -> &Location {
        &self.location
    }

    /// Set the cause for this error.
    pub fn caused_by<X: 'static + error::Error>(mut self, cause: X) -> Self {
        self.cause = Some(Box::new(cause));

        self
    }

    /// Wraps this error inside another error as its cause.
    pub fn causes<X>(self, wrapper: Error<X>) -> Error<X> where
        X: ErrorCode
    {
        wrapper.caused_by(self)
    }

    /// Creates an iterator to iterate along the error cause-chain.
    pub fn iter(&self) -> ErrorIter {
        ErrorIter {
            next: Some(self),
        }
    }
}

impl<T> error::Error for Error<T>
    where T: ErrorCode
{
    fn description(&self) -> &str {
        // delegate the error description to the ErrorCode
        &self.code.description()
    }

    fn cause<'a>(&'a self) -> Option<&'a error::Error> {
        // dereference from Option<Box<T>> to Option<&T>
        self.cause.as_ref().map(|x| &**x)
    }
}

/// Iterator to iterate along the error cause-chain.
pub struct ErrorIter<'a> {
    next: Option<&'a error::Error>
}

impl<'a> Iterator for ErrorIter<'a> {
    type Item = &'a error::Error;

    fn next(&mut self) -> Option<Self::Item> {
        return match self.next {
            Some(err) => {
                self.next = err.cause();
                Some(err)
            }
            None => None,
        }
    }
}

impl<T> Display for Error<T>
    where T: ErrorCode
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{error_code} at {location}\n",
            error_code = self.code,
            location = self.location));

        match self.cause {
            None => Ok(()),
            Some(ref cause) => write!(f, " - caused by: {}", cause),
        }
    }
}

/// Location in rust source code
///
/// The Display trait is formatted like `"{filename}:{line}:{column}"`.
///
/// We just store everything we can get, to identify source code locations. Note that
/// the module_path is currently only displayed in Debug output due to this redundancy.
/// You can access all fields directly.
#[derive(Debug)]
pub struct Location {
    pub module_path : &'static str, // e.g. twig::lexer::job::state::shared_traits
    pub filename : &'static str,    // e.g. /src/lexer/job/state/shared_traits.rs
    pub line : u32,
    pub column : u32,
}

impl Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{filename}:{line}:{column}",
            filename = self.filename,
            line     = self.line,
            column   = self.column)
    }
}
<commit_msg>fix testcase<commit_after>// This file is part of Twig (ported to Rust).
//
// For the copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Twig Error Handling

use std::fmt::{self, Debug, Display};
use std::error;
use std::any::Any;

#[macro_use]
mod macros;
// use std Error-trait to improve cross-crate compatibility
// don't mix it up with Err(X)

/// Lightweight base functionality for error codes
///
/// Similar to std::error::Error, but _without_ error-chaining.
pub trait ErrorCode: Debug + Display + Any {
    /// A short description of the error code.
    ///
    /// The description should not contain newlines or sentence-ending
    /// punctuation, to facilitate embedding in larger user-facing
    /// strings.
    fn description(&self) -> &str;

    /// Returns generic twig error for this error code.
    /// You must provide the location, where the error occured.
    fn at(self, location: Location) -> Error<Self> where
        Self: Sized
    {
        Error::new(self, location)
    }
}

/// Reference implementation to make examples easier.
impl ErrorCode for &'static str {
    fn description(&self) -> &str { *self }
}

/// Transform ErrorCodes
///
/// It is different to the Into-trait, because we only take references.
pub trait GeneralizeTo<T> {
    fn generalize(&self) -> T;
}

/// Record current state of complex objects
///
/// Implement this trait for complex objects. Make sure, that the Dump::Data type
/// does not contain lifetimes to keep error codes simple. In practice this means
/// cloning all referenced data into the dump.
///
/// For any `X: Dump` you can
///
/// * reference the associated type via `<X as Dump>::Data`
/// * create the dump via `X.dump()`
pub trait Dump {
    type Data: Debug + Display + 'static;

    fn dump(&self) -> Self::Data;
}

/// Generic twig error
///
/// Wrapper around some `ErrorCode` - adds location support and error-chaining.
#[derive(Debug)]
pub struct Error<T>
    where T: ErrorCode
{
    // the exception codes are going to be enums
    // - i.e. Exception<MY_ENUM> implements std::error::Error without any boilerplate
    // to MY_ENUM. Hurray! :-)
    code: T,
    // I decided to call this field `code` instead of `error` to not confuse it with the Error trait
    location: Location,
    // chaining is required by std::error::Error
    cause: Option<Box<error::Error>>,
}

impl<T> Error<T>
    where T: ErrorCode
{
    /// Create a new twig error out of some generic error code.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use] extern crate twig;
    /// # fn main() {
    /// use twig::error::Error;
    ///
    /// Error::new("my error", loc!()); // shorthand: `err!("my error")`
    /// # }
    /// ```
    pub fn new(code: T, location: Location) -> Error<T> {
        Error {
            code: code,
            location: location,
            cause: None
        }
    }

    /// Return the associated error code.
    #[allow(dead_code)] // only used by tests
    pub fn code(&self) -> &T {
        &self.code
    }

    /// Return the location the error occured.
    pub fn location(&self) -> &Location {
        &self.location
    }

    /// Set the cause for this error.
    pub fn caused_by<X: 'static + error::Error>(mut self, cause: X) -> Self {
        self.cause = Some(Box::new(cause));

        self
    }

    /// Wraps this error inside another error as its cause.
    pub fn causes<X>(self, wrapper: Error<X>) -> Error<X> where
        X: ErrorCode
    {
        wrapper.caused_by(self)
    }

    /// Creates an iterator to iterate along the error cause-chain.
    pub fn iter(&self) -> ErrorIter {
        ErrorIter {
            next: Some(self),
        }
    }
}

impl<T> error::Error for Error<T>
    where T: ErrorCode
{
    fn description(&self) -> &str {
        // delegate the error description to the ErrorCode
        &self.code.description()
    }

    fn cause<'a>(&'a self) -> Option<&'a error::Error> {
        // dereference from Option<Box<T>> to Option<&T>
        self.cause.as_ref().map(|x| &**x)
    }
}

/// Iterator to iterate along the error cause-chain.
pub struct ErrorIter<'a> {
    next: Option<&'a error::Error>
}

impl<'a> Iterator for ErrorIter<'a> {
    type Item = &'a error::Error;

    fn next(&mut self) -> Option<Self::Item> {
        return match self.next {
            Some(err) => {
                self.next = err.cause();
                Some(err)
            }
            None => None,
        }
    }
}

impl<T> Display for Error<T>
    where T: ErrorCode
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{error_code} at {location}\n",
            error_code = self.code,
            location = self.location));

        match self.cause {
            None => Ok(()),
            Some(ref cause) => write!(f, " - caused by: {}", cause),
        }
    }
}

/// Location in rust source code
///
/// The Display trait is formatted like `"{filename}:{line}:{column}"`.
///
/// We just store everything we can get, to identify source code locations. Note that
/// the module_path is currently only displayed in Debug output due to this redundancy.
/// You can access all fields directly.
#[derive(Debug)]
pub struct Location {
    pub module_path : &'static str, // e.g. twig::lexer::job::state::shared_traits
    pub filename : &'static str,    // e.g. /src/lexer/job/state/shared_traits.rs
    pub line : u32,
    pub column : u32,
}

impl Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{filename}:{line}:{column}",
            filename = self.filename,
            line     = self.line,
            column   = self.column)
    }
}
<|endoftext|>