<commit_before>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std::cmp::{Ordering, PartialOrd};
use std::env;
use std::fs::{self, DirEntry, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use error::{Error, Result};
use fs::PACKAGE_HOME;
use package::{MetaFile, PackageIdent};

const SUP_PKG_ORIGIN: &'static str = "chef";
const SUP_PKG_NAME: &'static str = "bldr";

#[derive(Clone, Debug)]
pub struct PackageInstall {
    ident: PackageIdent,
    installed_path: PathBuf,
    package_root_path: PathBuf,
}

impl PackageInstall {
    /// Verifies an installation of a package is within the package home and returns a struct
    /// representing that package installation.
    ///
    /// Only the origin and name of a package are required - the latest version/release of a
    /// package will be returned if their optional value is not specified. If only a version is
    /// specified, the latest release of that package origin, name, and version is returned.
    ///
    /// An optional `home` path may be provided to search for a package in a non-default path.
    pub fn load(ident: &PackageIdent, home: Option<&Path>) -> Result<PackageInstall> {
        let path = home.unwrap_or(Path::new(PACKAGE_HOME));
        let pl = try!(Self::package_list(path));
        if ident.fully_qualified() {
            if pl.iter().any(|ref p| p.satisfies(ident)) {
                Ok(PackageInstall {
                    ident: ident.clone(),
                    installed_path: try!(Self::calc_installed_path(ident, path)),
                    package_root_path: PathBuf::from(path),
                })
            } else {
                Err(Error::PackageNotFound(ident.clone()))
            }
        } else {
            let latest: Option<PackageIdent> = pl.iter()
                                                 .filter(|&p| p.satisfies(ident))
                                                 .fold(None, |winner, b| {
                                                     match winner {
                                                         Some(a) => {
                                                             match a.partial_cmp(&b) {
                                                                 Some(Ordering::Greater) => Some(a),
                                                                 Some(Ordering::Equal) => Some(a),
                                                                 Some(Ordering::Less) => {
                                                                     Some(b.clone())
                                                                 }
                                                                 None => Some(a),
                                                             }
                                                         }
                                                         None => Some(b.clone()),
                                                     }
                                                 });
            if let Some(id) = latest {
                Ok(PackageInstall {
                    ident: id.clone(),
                    installed_path: try!(Self::calc_installed_path(&id, path)),
                    package_root_path: PathBuf::from(path),
                })
            } else {
                Err(Error::PackageNotFound(ident.clone()))
            }
        }
    }

    pub fn new_from_parts(ident: PackageIdent,
                          installed_path: PathBuf,
                          package_root_path: PathBuf)
                          -> PackageInstall {
        PackageInstall {
            ident: ident,
            installed_path: installed_path,
            package_root_path: package_root_path,
        }
    }

    pub fn deps(&self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::Deps)
    }

    pub fn tdeps(&self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::TDeps)
    }

    /// A vector of ports we expose
    pub fn exposes(&self) -> Result<Vec<String>> {
        match self.read_metafile(MetaFile::Exposes) {
            Ok(body) => {
                let v: Vec<String> = body.split(' ')
                                         .map(|x| String::from(x.trim_right_matches('\n')))
                                         .collect();
                Ok(v)
            }
            Err(Error::MetaFileNotFound(MetaFile::Exposes)) => {
                let v: Vec<String> = Vec::new();
                Ok(v)
            }
            Err(e) => Err(e),
        }
    }

    pub fn ident(&self) -> &PackageIdent {
        &self.ident
    }

    /// Return the PATH string from the package metadata, if it exists
    ///
    /// # Failures
    ///
    /// * The package contains a Path metafile but it could not be read or it was malformed
    pub fn path(&self) -> Result<Option<PathBuf>> {
        match self.read_metafile(MetaFile::Path) {
            Ok(body) => Ok(Some(PathBuf::from(body))),
            Err(Error::MetaFileNotFound(MetaFile::Path)) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Returns a `String` with the full run path for this package. This path is composed of any
    /// binary paths specified by this package, or its TDEPS, plus the Supervisor or its TDEPS,
    /// plus the existing value of the PATH variable.
    ///
    /// This means we work on any operating system, as long as you can invoke the Supervisor,
    /// without having to worry much about context.
    pub fn runtime_path(&self) -> Result<String> {
        let mut run_path = String::new();
        if let Some(path) = try!(self.path()) {
            run_path.push_str(&path.to_string_lossy());
        }
        let tdeps: Vec<PackageInstall> = try!(self.load_tdeps());
        for dep in tdeps.iter() {
            if let Some(path) = try!(dep.path()) {
                run_path.push(':');
                run_path.push_str(&path.to_string_lossy());
            }
        }
        if self.ident.name != SUP_PKG_NAME {
            let sup_pkg = try!(Self::load(&PackageIdent::new(SUP_PKG_ORIGIN,
                                                             SUP_PKG_NAME,
                                                             None,
                                                             None),
                                          Some(&self.package_root_path)));
            if let Some(path) = try!(sup_pkg.path()) {
                run_path.push(':');
                run_path.push_str(&path.to_string_lossy());
            }
            let tdeps: Vec<PackageInstall> = try!(sup_pkg.load_tdeps());
            for dep in tdeps.iter() {
                if let Some(path) = try!(dep.path()) {
                    run_path.push(':');
                    run_path.push_str(&path.to_string_lossy());
                }
            }
        }
        if let Some(val) = env::var_os("PATH") {
            run_path.push(':');
            run_path.push_str(&val.to_string_lossy());
        }
        Ok(run_path)
    }

    pub fn installed_path(&self) -> &PathBuf {
        &self.installed_path
    }

    /// Read the contents of a given metafile.
    ///
    /// # Failures
    ///
    /// * A metafile could not be found
    /// * Contents of the metafile could not be read
    /// * Contents of the metafile are unreadable or malformed
    fn read_metafile(&self, file: MetaFile) -> Result<String> {
        let filepath = self.installed_path.join(file.to_string());
        match fs::metadata(&filepath) {
            Ok(_) => {
                match File::open(&filepath) {
                    Ok(mut f) => {
                        let mut data = String::new();
                        if f.read_to_string(&mut data).is_err() {
                            return Err(Error::MetaFileMalformed(file));
                        }
                        Ok(data.trim().to_string())
                    }
                    Err(e) => Err(Error::MetaFileIO(e)),
                }
            }
            Err(_) => Err(Error::MetaFileNotFound(file)),
        }
    }

    /// Reads metafiles containing dependencies represented by package identifiers separated by new
    /// lines.
    ///
    /// # Failures
    ///
    /// * Metafile could not be found
    /// * Contents of the metafile could not be read
    /// * Contents of the metafile are unreadable or malformed
    fn read_deps(&self, file: MetaFile) -> Result<Vec<PackageIdent>> {
        let mut deps: Vec<PackageIdent> = vec![];
        match self.read_metafile(file) {
            Ok(body) => {
                let ids: Vec<String> = body.split("\n").map(|d| d.to_string()).collect();
                for id in &ids {
                    let package = try!(PackageIdent::from_str(id));
                    if !package.fully_qualified() {
                        return Err(Error::InvalidPackageIdent(package.to_string()));
                    }
                    deps.push(package);
                }
                Ok(deps)
            }
            Err(Error::MetaFileNotFound(_)) => Ok(deps),
            Err(e) => Err(e),
        }
    }

    /// Attempts to load the extracted package for each transitive dependency and returns a
    /// `Package` struct representation of each in the returned vector.
    ///
    /// # Failures
    ///
    /// * Any transitive dependency could not be located or it's contents could not be read
    ///   from disk
    fn load_tdeps(&self) -> Result<Vec<PackageInstall>> {
        let tdeps = try!(self.tdeps());
        let mut deps = Vec::with_capacity(tdeps.len());
        for dep in tdeps.iter() {
            let dep_install = try!(Self::load(dep, Some(&self.package_root_path)));
            deps.push(dep_install);
        }
        Ok(deps)
    }

    fn calc_installed_path(ident: &PackageIdent, pkg_root: &Path) -> Result<PathBuf> {
        if ident.fully_qualified() {
            Ok(pkg_root.join(&ident.origin)
                       .join(&ident.name)
                       .join(ident.version.as_ref().unwrap())
                       .join(ident.release.as_ref().unwrap()))
        } else {
            Err(Error::PackageNotFound(ident.clone()))
        }
    }

    /// Returns a list of package structs built from the contents of the given directory.
    fn package_list(path: &Path) -> Result<Vec<PackageIdent>> {
        let mut package_list: Vec<PackageIdent> = vec![];
        if try!(fs::metadata(path)).is_dir() {
            try!(Self::walk_origins(&path, &mut package_list));
        }
        Ok(package_list)
    }

    /// Helper function for package_list. Walks the given path for origin directories
    /// and builds on the given package list by recursing into name, version, and release
    /// directories.
    fn walk_origins(path: &Path, packages: &mut Vec<PackageIdent>) -> Result<()> {
        for entry in try!(fs::read_dir(path)) {
            let origin = try!(entry);
            if try!(fs::metadata(origin.path())).is_dir() {
                try!(Self::walk_names(&origin, packages));
            }
        }
        Ok(())
    }

    /// Helper function for walk_origins. Walks the given origin DirEntry for name
    /// directories and recurses into them to find version and release directories.
    fn walk_names(origin: &DirEntry, packages: &mut Vec<PackageIdent>) -> Result<()> {
        for name in try!(fs::read_dir(origin.path())) {
            let name = try!(name);
            let origin = origin.file_name().to_string_lossy().into_owned().to_string();
            if try!(fs::metadata(name.path())).is_dir() {
                try!(Self::walk_versions(&origin, &name, packages));
            }
        }
        Ok(())
    }

    /// Helper fuction for walk_names. Walks the given name DirEntry for directories and recurses
    /// into them to find release directories.
    fn walk_versions(origin: &String,
                     name: &DirEntry,
                     packages: &mut Vec<PackageIdent>)
                     -> Result<()> {
        for version in try!(fs::read_dir(name.path())) {
            let version = try!(version);
            let name = name.file_name().to_string_lossy().into_owned().to_string();
            if try!(fs::metadata(version.path())).is_dir() {
                try!(Self::walk_releases(origin, &name, &version, packages));
            }
        }
        Ok(())
    }

    /// Helper function for walk_versions. Walks the given release DirEntry for directories and recurses
    /// into them to find version directories. Finally, a Package struct is built and concatenated onto
    /// the given packages vector with the origin, name, version, and release of each.
    fn walk_releases(origin: &String,
                     name: &String,
                     version: &DirEntry,
                     packages: &mut Vec<PackageIdent>)
                     -> Result<()> {
        for release in try!(fs::read_dir(version.path())) {
            let release = try!(release).file_name().to_string_lossy().into_owned().to_string();
            let version = version.file_name().to_string_lossy().into_owned().to_string();
            let ident = PackageIdent::new(origin.clone(),
                                          name.clone(),
                                          Some(version),
                                          Some(release));
            packages.push(ident)
        }
        Ok(())
    }
}
<commit_msg>[hab] Automatically installs `hab-sup` if missing when invoked.<commit_after>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std::cmp::{Ordering, PartialOrd};
use std::env;
use std::fs::{self, DirEntry, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use error::{Error, Result};
use fs::PACKAGE_HOME;
use package::{MetaFile, PackageIdent};

const SUP_PKG_ORIGIN: &'static str = "chef";
const SUP_PKG_NAME: &'static str = "bldr";

#[derive(Clone, Debug)]
pub struct PackageInstall {
    ident: PackageIdent,
    installed_path: PathBuf,
    package_root_path: PathBuf,
}

impl PackageInstall {
    /// Verifies an installation of a package is within the package home and returns a struct
    /// representing that package installation.
    ///
    /// Only the origin and name of a package are required - the latest version/release of a
    /// package will be returned if their optional value is not specified. If only a version is
    /// specified, the latest release of that package origin, name, and version is returned.
    ///
    /// An optional `home` path may be provided to search for a package in a non-default path.
    pub fn load(ident: &PackageIdent, home: Option<&Path>) -> Result<PackageInstall> {
        let path = home.unwrap_or(Path::new(PACKAGE_HOME));
        let pl = try!(Self::package_list(path));
        if ident.fully_qualified() {
            if pl.iter().any(|ref p| p.satisfies(ident)) {
                Ok(PackageInstall {
                    ident: ident.clone(),
                    installed_path: try!(Self::calc_installed_path(ident, path)),
                    package_root_path: PathBuf::from(path),
                })
            } else {
                Err(Error::PackageNotFound(ident.clone()))
            }
        } else {
            let latest: Option<PackageIdent> = pl.iter()
                                                 .filter(|&p| p.satisfies(ident))
                                                 .fold(None, |winner, b| {
                                                     match winner {
                                                         Some(a) => {
                                                             match a.partial_cmp(&b) {
                                                                 Some(Ordering::Greater) => Some(a),
                                                                 Some(Ordering::Equal) => Some(a),
                                                                 Some(Ordering::Less) => {
                                                                     Some(b.clone())
                                                                 }
                                                                 None => Some(a),
                                                             }
                                                         }
                                                         None => Some(b.clone()),
                                                     }
                                                 });
            if let Some(id) = latest {
                Ok(PackageInstall {
                    ident: id.clone(),
                    installed_path: try!(Self::calc_installed_path(&id, path)),
                    package_root_path: PathBuf::from(path),
                })
            } else {
                Err(Error::PackageNotFound(ident.clone()))
            }
        }
    }

    pub fn new_from_parts(ident: PackageIdent,
                          installed_path: PathBuf,
                          package_root_path: PathBuf)
                          -> PackageInstall {
        PackageInstall {
            ident: ident,
            installed_path: installed_path,
            package_root_path: package_root_path,
        }
    }

    pub fn deps(&self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::Deps)
    }

    pub fn tdeps(&self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::TDeps)
    }

    /// A vector of ports we expose
    pub fn exposes(&self) -> Result<Vec<String>> {
        match self.read_metafile(MetaFile::Exposes) {
            Ok(body) => {
                let v: Vec<String> = body.split(' ')
                                         .map(|x| String::from(x.trim_right_matches('\n')))
                                         .collect();
                Ok(v)
            }
            Err(Error::MetaFileNotFound(MetaFile::Exposes)) => {
                let v: Vec<String> = Vec::new();
                Ok(v)
            }
            Err(e) => Err(e),
        }
    }

    pub fn ident(&self) -> &PackageIdent {
        &self.ident
    }

    /// Return the PATH string from the package metadata, if it exists
    ///
    /// # Failures
    ///
    /// * The package contains a Path metafile but it could not be read or it was malformed
    pub fn paths(&self) -> Result<Vec<PathBuf>> {
        match self.read_metafile(MetaFile::Path) {
            Ok(body) => {
                let v = env::split_paths(&body).map(|p| PathBuf::from(&p)).collect();
                Ok(v)
            }
            Err(Error::MetaFileNotFound(MetaFile::Path)) => {
                let v: Vec<PathBuf> = Vec::new();
                Ok(v)
            }
            Err(e) => Err(e),
        }
    }

    /// Returns a `String` with the full run path for this package. This path is composed of any
    /// binary paths specified by this package, or its TDEPS, plus the Supervisor or its TDEPS,
    /// plus the existing value of the PATH variable.
    ///
    /// This means we work on any operating system, as long as you can invoke the Supervisor,
    /// without having to worry much about context.
    pub fn runtime_path(&self) -> Result<String> {
        let mut run_path = String::new();
        for path in try!(self.paths()) {
            run_path.push_str(&path.to_string_lossy());
        }
        let tdeps: Vec<PackageInstall> = try!(self.load_tdeps());
        for dep in tdeps.iter() {
            for path in try!(dep.paths()) {
                run_path.push(':');
                run_path.push_str(&path.to_string_lossy());
            }
        }
        if self.ident.name != SUP_PKG_NAME {
            let sup_pkg = try!(Self::load(&PackageIdent::new(SUP_PKG_ORIGIN,
                                                             SUP_PKG_NAME,
                                                             None,
                                                             None),
                                          Some(&self.package_root_path)));
            for path in try!(sup_pkg.paths()) {
                run_path.push(':');
                run_path.push_str(&path.to_string_lossy());
            }
            let tdeps: Vec<PackageInstall> = try!(sup_pkg.load_tdeps());
            for dep in tdeps.iter() {
                for path in try!(dep.paths()) {
                    run_path.push(':');
                    run_path.push_str(&path.to_string_lossy());
                }
            }
        }
        if let Some(val) = env::var_os("PATH") {
            run_path.push(':');
            run_path.push_str(&val.to_string_lossy());
        }
        Ok(run_path)
    }

    pub fn installed_path(&self) -> &PathBuf {
        &self.installed_path
    }

    /// Read the contents of a given metafile.
    ///
    /// # Failures
    ///
    /// * A metafile could not be found
    /// * Contents of the metafile could not be read
    /// * Contents of the metafile are unreadable or malformed
    fn read_metafile(&self, file: MetaFile) -> Result<String> {
        let filepath = self.installed_path.join(file.to_string());
        match fs::metadata(&filepath) {
            Ok(_) => {
                match File::open(&filepath) {
                    Ok(mut f) => {
                        let mut data = String::new();
                        if f.read_to_string(&mut data).is_err() {
                            return Err(Error::MetaFileMalformed(file));
                        }
                        Ok(data.trim().to_string())
                    }
                    Err(e) => Err(Error::MetaFileIO(e)),
                }
            }
            Err(_) => Err(Error::MetaFileNotFound(file)),
        }
    }

    /// Reads metafiles containing dependencies represented by package identifiers separated by new
    /// lines.
    ///
    /// # Failures
    ///
    /// * Metafile could not be found
    /// * Contents of the metafile could not be read
    /// * Contents of the metafile are unreadable or malformed
    fn read_deps(&self, file: MetaFile) -> Result<Vec<PackageIdent>> {
        let mut deps: Vec<PackageIdent> = vec![];
        match self.read_metafile(file) {
            Ok(body) => {
                let ids: Vec<String> = body.split("\n").map(|d| d.to_string()).collect();
                for id in &ids {
                    let package = try!(PackageIdent::from_str(id));
                    if !package.fully_qualified() {
                        return Err(Error::InvalidPackageIdent(package.to_string()));
                    }
                    deps.push(package);
                }
                Ok(deps)
            }
            Err(Error::MetaFileNotFound(_)) => Ok(deps),
            Err(e) => Err(e),
        }
    }

    /// Attempts to load the extracted package for each transitive dependency and returns a
    /// `Package` struct representation of each in the returned vector.
    ///
    /// # Failures
    ///
    /// * Any transitive dependency could not be located or it's contents could not be read
    ///   from disk
    fn load_tdeps(&self) -> Result<Vec<PackageInstall>> {
        let tdeps = try!(self.tdeps());
        let mut deps = Vec::with_capacity(tdeps.len());
        for dep in tdeps.iter() {
            let dep_install = try!(Self::load(dep, Some(&self.package_root_path)));
            deps.push(dep_install);
        }
        Ok(deps)
    }

    fn calc_installed_path(ident: &PackageIdent, pkg_root: &Path) -> Result<PathBuf> {
        if ident.fully_qualified() {
            Ok(pkg_root.join(&ident.origin)
                       .join(&ident.name)
                       .join(ident.version.as_ref().unwrap())
                       .join(ident.release.as_ref().unwrap()))
        } else {
            Err(Error::PackageNotFound(ident.clone()))
        }
    }

    /// Returns a list of package structs built from the contents of the given directory.
    fn package_list(path: &Path) -> Result<Vec<PackageIdent>> {
        let mut package_list: Vec<PackageIdent> = vec![];
        if try!(fs::metadata(path)).is_dir() {
            try!(Self::walk_origins(&path, &mut package_list));
        }
        Ok(package_list)
    }

    /// Helper function for package_list. Walks the given path for origin directories
    /// and builds on the given package list by recursing into name, version, and release
    /// directories.
    fn walk_origins(path: &Path, packages: &mut Vec<PackageIdent>) -> Result<()> {
        for entry in try!(fs::read_dir(path)) {
            let origin = try!(entry);
            if try!(fs::metadata(origin.path())).is_dir() {
                try!(Self::walk_names(&origin, packages));
            }
        }
        Ok(())
    }

    /// Helper function for walk_origins. Walks the given origin DirEntry for name
    /// directories and recurses into them to find version and release directories.
    fn walk_names(origin: &DirEntry, packages: &mut Vec<PackageIdent>) -> Result<()> {
        for name in try!(fs::read_dir(origin.path())) {
            let name = try!(name);
            let origin = origin.file_name().to_string_lossy().into_owned().to_string();
            if try!(fs::metadata(name.path())).is_dir() {
                try!(Self::walk_versions(&origin, &name, packages));
            }
        }
        Ok(())
    }

    /// Helper fuction for walk_names. Walks the given name DirEntry for directories and recurses
    /// into them to find release directories.
    fn walk_versions(origin: &String,
                     name: &DirEntry,
                     packages: &mut Vec<PackageIdent>)
                     -> Result<()> {
        for version in try!(fs::read_dir(name.path())) {
            let version = try!(version);
            let name = name.file_name().to_string_lossy().into_owned().to_string();
            if try!(fs::metadata(version.path())).is_dir() {
                try!(Self::walk_releases(origin, &name, &version, packages));
            }
        }
        Ok(())
    }

    /// Helper function for walk_versions. Walks the given release DirEntry for directories and recurses
    /// into them to find version directories. Finally, a Package struct is built and concatenated onto
    /// the given packages vector with the origin, name, version, and release of each.
    fn walk_releases(origin: &String,
                     name: &String,
                     version: &DirEntry,
                     packages: &mut Vec<PackageIdent>)
                     -> Result<()> {
        for release in try!(fs::read_dir(version.path())) {
            let release = try!(release).file_name().to_string_lossy().into_owned().to_string();
            let version = version.file_name().to_string_lossy().into_owned().to_string();
            let ident = PackageIdent::new(origin.clone(),
                                          name.clone(),
                                          Some(version),
                                          Some(release));
            packages.push(ident)
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! metadata handles parsing of GPX-spec metadata.

use errors::*;
use std::io::Read;
use xml::reader::XmlEvent;

use parser::link;
use parser::string;
use parser::person;
use parser::time;
use parser::bounds;
use parser::Context;

use Metadata;

enum ParseEvent {
    StartName,
    StartDescription,
    StartAuthor,
    StartKeywords,
    StartTime,
    StartLink,
    StartBounds,
    Ignore,
    EndMetadata,
}

pub fn consume<R: Read>(context: &mut Context<R>) -> Result<Metadata> {
    let mut metadata: Metadata = Default::default();

    loop {
        // Peep into the reader and see what type of event is next. Based on
        // that information, we'll either forward the event to a downstream
        // module or take the information for ourselves.
        let event: Result<ParseEvent> = {
            if let Some(next) = context.reader.peek() {
                match next {
                    &Ok(XmlEvent::StartElement { ref name, .. }) => {
                        match name.local_name.as_ref() {
                            "metadata" => Ok(ParseEvent::Ignore),
                            "name" => Ok(ParseEvent::StartName),
                            "description" => Ok(ParseEvent::StartDescription),
                            "author" => Ok(ParseEvent::StartAuthor),
                            "keywords" => Ok(ParseEvent::StartKeywords),
                            "time" => Ok(ParseEvent::StartTime),
                            "link" => Ok(ParseEvent::StartLink),
                            "bounds" => Ok(ParseEvent::StartBounds),
                            child => Err(Error::from(ErrorKind::InvalidChildElement(
                                String::from(child),
                                "metadata",
                            )))?,
                        }
                    }

                    &Ok(XmlEvent::EndElement { .. }) => Ok(ParseEvent::EndMetadata),

                    _ => Ok(ParseEvent::Ignore),
                }
            } else {
                break;
            }
        };

        match event.chain_err(|| Error::from("error while parsing gpx event"))? {
            ParseEvent::Ignore => {
                context.reader.next();
            }

            ParseEvent::StartName => {
                metadata.name = Some(string::consume(context)?);
            }

            ParseEvent::StartDescription => {
                metadata.description = Some(string::consume(context)?);
            }

            ParseEvent::StartAuthor => {
                metadata.author = Some(person::consume(context)?);
            }

            ParseEvent::StartKeywords => {
                metadata.keywords = Some(string::consume(context)?);
            }

            ParseEvent::StartTime => {
                metadata.time = Some(time::consume(context)?);
            }

            ParseEvent::StartLink => {
                metadata.links.push(link::consume(context)?);
            }

            ParseEvent::StartBounds => {
                metadata.bounds = Some(bounds::consume(context)?);
            }

            ParseEvent::EndMetadata => {
                context.reader.next();

                return Ok(metadata);
            }
        }
    }

    return Err("no end tag for metadata".into());
}

#[cfg(test)]
mod tests {
    use std::io::BufReader;
    use xml::reader::EventReader;
    use chrono::prelude::*;

    use GpxVersion;
    use parser::Context;
    use super::consume;

    #[test]
    fn consume_empty() {
        let result = consume!("<metadata></metadata>", GpxVersion::Gpx11);

        assert!(result.is_ok());

        let result = result.unwrap();
        assert!(result.name.is_none());
        assert!(result.description.is_none());
        assert!(result.author.is_none());
        assert!(result.keywords.is_none());
        assert!(result.time.is_none());
    }

    #[test]
    fn consume_metadata() {
        let result = consume!(
            "
            <metadata>
                <link href=\"example.com\" />
                <name>xxname</name>
                <description>xxdescription</description>
                <author>
                    <name>John Doe</name>
                    <email id=\"john.doe\" domain=\"example.com\" />
                    <link href=\"example.com\">
                        <text>hello world</text>
                        <type>some type</type>
                    </link>
                </author>
                <keywords>some keywords here</keywords>
                <time>2017-08-16T04:03:33.735Z</time>
            </metadata>
            ",
            GpxVersion::Gpx11
        );

        assert!(result.is_ok());

        let result = result.unwrap();

        assert!(result.name.is_some());
        assert_eq!(result.name.unwrap(), "xxname");

        assert!(result.description.is_some());
        assert_eq!(result.description.unwrap(), "xxdescription");

        assert!(result.author.is_some());
        let author = result.author.unwrap();

        assert_eq!(author.name.unwrap(), "John Doe");
        assert_eq!(author.email.unwrap(), "john.doe@example.com");
        assert_eq!(author.link.unwrap().href, "example.com");

        assert!(result.keywords.is_some());
        assert_eq!(result.keywords.unwrap(), "some keywords here");

        assert!(result.time.is_some());
        assert_eq!(
            result.time.unwrap(),
            Utc.ymd(2017, 8, 16).and_hms_micro(4, 3, 33, 735_000)
        );

        assert_eq!(result.links.len(), 1);
    }
}
<commit_msg>Rewrite metadata::consume cleaner and more strict - Do not accept arbitrary amounts of opening metadata tags, we require   exactly one at the beginning and do not allow further ones - Do not accept any closing tag as tag that closes metadata, require   name==metadata - Use new custom errors InvalidClosingTag and MissingClosingTag - Avoid indirection of ParseEvents, handle XmlEvents more directly<commit_after>//! metadata handles parsing of GPX-spec metadata.

use errors::*;
use std::io::Read;
use xml::reader::XmlEvent;

use parser::link;
use parser::string;
use parser::person;
use parser::time;
use parser::bounds;
use parser::Context;
use parser::verify_starting_tag;

use Metadata;

pub fn consume<R: Read>(context: &mut Context<R>) -> Result<Metadata> {
    let mut metadata: Metadata = Default::default();
    verify_starting_tag(context, "metadata")?;

    loop {
        let next_event = {
            if let Some(next) = context.reader.peek() {
                next.clone()
            } else {
                break;
            }
        };

        match next_event.chain_err(|| Error::from("error while parsing metadata event"))? {
            XmlEvent::StartElement { ref name, .. } => match name.local_name.as_ref() {
                "name" => {
                    metadata.name = Some(string::consume(context)?);
                }
                "description" => {
                    metadata.description = Some(string::consume(context)?);
                }
                "author" => {
                    metadata.author = Some(person::consume(context)?);
                }
                "keywords" => {
                    metadata.keywords = Some(string::consume(context)?);
                }
                "time" => {
                    metadata.time = Some(time::consume(context)?);
                }
                "link" => {
                    metadata.links.push(link::consume(context)?);
                }
                "bounds" => {
                    metadata.bounds = Some(bounds::consume(context)?);
                }
                child => {
                    bail!(ErrorKind::InvalidChildElement(
                        String::from(child),
                        "metadata"
                    ));
                }
            },
            XmlEvent::EndElement { ref name } => {
                ensure!(
                    name.local_name == "metadata",
                    ErrorKind::InvalidClosingTag(name.local_name.clone(), "metadata")
                );
                context.reader.next(); //consume the end tag
                return Ok(metadata);
            }
            _ => {
                context.reader.next(); //consume and ignore this event
            }
        }
    }

    bail!(ErrorKind::MissingClosingTag("metadata"));
}

#[cfg(test)]
mod tests {
    use std::io::BufReader;
    use xml::reader::EventReader;
    use chrono::prelude::*;

    use GpxVersion;
    use parser::Context;
    use super::consume;

    #[test]
    fn consume_empty() {
        let result = consume!("<metadata></metadata>", GpxVersion::Gpx11);

        assert!(result.is_ok());

        let result = result.unwrap();
        assert!(result.name.is_none());
        assert!(result.description.is_none());
        assert!(result.author.is_none());
        assert!(result.keywords.is_none());
        assert!(result.time.is_none());
    }

    #[test]
    fn consume_metadata() {
        let result = consume!(
            "
            <metadata>
                <link href=\"example.com\" />
                <name>xxname</name>
                <description>xxdescription</description>
                <author>
                    <name>John Doe</name>
                    <email id=\"john.doe\" domain=\"example.com\" />
                    <link href=\"example.com\">
                        <text>hello world</text>
                        <type>some type</type>
                    </link>
                </author>
                <keywords>some keywords here</keywords>
                <time>2017-08-16T04:03:33.735Z</time>
            </metadata>
            ",
            GpxVersion::Gpx11
        );

        assert!(result.is_ok());

        let result = result.unwrap();

        assert!(result.name.is_some());
        assert_eq!(result.name.unwrap(), "xxname");

        assert!(result.description.is_some());
        assert_eq!(result.description.unwrap(), "xxdescription");

        assert!(result.author.is_some());
        let author = result.author.unwrap();

        assert_eq!(author.name.unwrap(), "John Doe");
        assert_eq!(author.email.unwrap(), "john.doe@example.com");
        assert_eq!(author.link.unwrap().href, "example.com");

        assert!(result.keywords.is_some());
        assert_eq!(result.keywords.unwrap(), "some keywords here");

        assert!(result.time.is_some());
        assert_eq!(
            result.time.unwrap(),
            Utc.ymd(2017, 8, 16).and_hms_micro(4, 3, 33, 735_000)
        );

        assert_eq!(result.links.len(), 1);
    }
}
<|endoftext|>


<commit_before>//! Various helpers for code-generation.

use std::io;
use std::cmp;
use std::char;
use std::iter;
use std::usize;
use std::ops::{Add, AddAssign, Range};
#[cfg(test)]
use std::iter::FromIterator;

use super::{Atom, Class, ClassMember};

// ================================================================
/// Trait for atom types that can be converted to byte sequences.
pub trait Bytes<'a> {
    /// Iterator type returned by `bytes`.
    type Iter: 'a + Iterator<Item=u8>;

    /// Fetch an iterator over "self" as a series of bytes.
    fn bytes(&self) -> Self::Iter;
}

/// Interface for types which can bound the number of bytes required to match
/// a particular instance of themselves.
pub trait SizedRead {
    /// Get the size of this object when read directly from something
    /// implementing `std::io::Read`.
    fn read_size(&self) -> ReadSize;
}

/// Trait for use with fixed-size types
pub trait ReadToBuffer {
    /// Read at most `max_count` instances of this atom type from the given
    /// stream, placing them into the supplied buffer.
    fn read_to_buffer<R>(r: &mut R, dest: &mut [u8], max_count: usize) -> io::Result<usize>
        where R: io::Read;
}

/// Possible results from `SizedRead::read_size`
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ReadSize {
    /// Exact size is known in advance
    Exact(usize),

    /// Size can be within the given range of values.
    Range(usize, usize)
}

impl ReadSize {
    /// Get the minimum number of bytes specified by this ReadSize.
    #[inline]
    fn min(&self) -> usize {
        match self {
            &ReadSize::Exact(s) => s,
            &ReadSize::Range(a, _) => a,
        }
    }
    /// Get the maximum number of bytes specified by this ReadSize.
    #[inline]
    fn max(&self) -> usize {
        match self {
            &ReadSize::Exact(s) => s,
            &ReadSize::Range(_, b) => b,
        }
    }

}

impl iter::Sum<ReadSize> for ReadSize {
    #[inline]
    fn sum<I>(iter: I) -> Self where I: Iterator<Item=ReadSize> {
        let mut sum = ReadSize::Exact(0);
        for rs in iter {
            sum += rs;
        }
        sum
    }
}

impl Add<ReadSize> for ReadSize {
    type Output = ReadSize;
    #[inline]
    fn add(self, rhs: ReadSize) -> Self::Output {
        let min = self.min() + rhs.min();
        let max = self.max() + rhs.max();
        if min == max { ReadSize::Exact(min) }
        else { ReadSize::Range(min, max) }
    }
}

impl AddAssign<ReadSize> for ReadSize {
    #[inline]
    fn add_assign(&mut self, rhs: ReadSize) {
        *self = *self + rhs;
    }
}

impl From<usize> for ReadSize {
    #[inline]
    fn from(s: usize) -> Self {
        ReadSize::Exact(s)
    }
}

impl From<Range<usize>> for ReadSize {
    #[inline]
    fn from(r: Range<usize>) -> Self {
        if r.len() > 1 { ReadSize::Range(r.start, r.end - 1) }
        else { ReadSize::Exact(r.start) }
    }
}

// ----------------------------------------------------------------
// Implementations

impl<'a> Bytes<'a> for u8 {
    type Iter = iter::Once<u8>;
    fn bytes(&self) -> Self::Iter {
        iter::once(*self)
    }
}

// This table was copied from the Rust source tree,
// file "src/libcore/str/mod.rs".
// https://tools.ietf.org/html/rfc3629
static UTF8_CHAR_WIDTH: [u8; 256] = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF
0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF
4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF
];

impl<'a> Bytes<'a> for char {
    type Iter = char::EncodeUtf8;
    fn bytes(&self) -> Self::Iter {
        self.encode_utf8()
    }
}

impl SizedRead for char {
    #[inline]
    fn read_size(&self) -> ReadSize {
        self.len_utf8().into()
    }
}

impl ReadToBuffer for char {
    #[inline]
    fn read_to_buffer<R>(r: &mut R, dest: &mut [u8], max_count: usize) -> io::Result<usize>
        where R: io::Read {
        let mut i = 0;
        let mut n = 0;
        while i < dest.len() && n < max_count {
            try!(r.read_exact(&mut dest[i..(i+1)]));
            let w = UTF8_CHAR_WIDTH[dest[i] as usize];
            try!(r.read_exact(&mut dest[(i+1)..(i + w as usize)]));
            i += w as usize;
            n += 1;
        }
        Ok(i)
    }

}

#[cfg(test)]
#[test]
fn test_sizedread_char() {
    assert_eq!(ReadSize::Exact(1), 'a'.read_size());
    assert_eq!(ReadSize::Exact(3), '✓'.read_size());
}

#[cfg(test)]
#[test]
fn test_readable_char() {
    let mut buf = ['\0' as u8; 32];
    {
        let mut r = io::repeat('a' as u8);
        assert_eq!(3, char::read_to_buffer(&mut r, &mut buf, 3).unwrap());
        assert_eq!(&['a' as u8 as u8, 'a' as u8, 'a' as u8, '\0' as u8], &buf[0..4]);
    }

    {
        let s = "✓☠⚔";
        let mut r = io::Cursor::new(s.as_bytes());
        assert_eq!(9, char::read_to_buffer(&mut r, &mut buf, 3).unwrap());
        assert_eq!(s.as_bytes(), &buf[0..9]);
    }
}

// ----------------------------------------------------------------

/*impl<T> SizedRead for Transition<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        match self {
            &Transition::Atom(a) => a.read_size(),
            &Transition::Literal(ref atoms) => atoms.iter().map(|a| a.read_size()).sum(),
            &Transition::Wildcard => ReadSize::Range(1, 4),
            &Transition::Anchor(..) => ReadSize::Exact(0),
            &Transition::Class(ref c) => c.read_size(),
        }
    }
}*/

#[cfg(test)]
#[test]
fn test_sizedread_transition() {
    assert_eq!(ReadSize::Exact(1), 'a'.read_size());
    assert_eq!(ReadSize::Exact(3), '✓'.read_size());
    assert_eq!(ReadSize::Range(1, 3), Class::from_iter(['x', 'y', '⚔'].into_iter().cloned()).read_size());
}

// ----------------------------------------------------------------

impl<T> SizedRead for ClassMember<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        match self {
            &ClassMember::Atom(a) => a.read_size(),
            &ClassMember::Range(first, last) => {
                // We'll assume that any differences in read size between
                // `first` and `last` follow a linear function between the two;
                // this _assumption_ allows us to avoid evaluating `read_size`
                // for every single member of the range.
                let frs = first.read_size();
                let lrs = last.read_size();
                (cmp::min(frs.min(), lrs.min())..(cmp::max(frs.max(), lrs.max()) + 1)).into()
            }
        }
    }
}

impl<T> SizedRead for Class<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        let mut min = usize::MAX;
        let mut max = usize::MIN;

        for m in self.iter_members() {
            let rs = m.read_size();
            min = cmp::min(min, rs.min());
            max = cmp::max(max, rs.max());
        }

        (min..(max + 1)).into()
    }
}

<commit_msg>pattern/codegen: impl SizedRead and ReadToBuffer for u8<commit_after>//! Various helpers for code-generation.

use std::io;
use std::cmp;
use std::char;
use std::iter;
use std::usize;
use std::ops::{Add, AddAssign, Range};
#[cfg(test)]
use std::iter::FromIterator;

use super::{Atom, Class, ClassMember};

// ================================================================
/// Trait for atom types that can be converted to byte sequences.
pub trait Bytes<'a> {
    /// Iterator type returned by `bytes`.
    type Iter: 'a + Iterator<Item=u8>;

    /// Fetch an iterator over "self" as a series of bytes.
    fn bytes(&self) -> Self::Iter;
}

/// Interface for types which can bound the number of bytes required to match
/// a particular instance of themselves.
pub trait SizedRead {
    /// Get the size of this object when read directly from something
    /// implementing `std::io::Read`.
    fn read_size(&self) -> ReadSize;
}

/// Trait for use with fixed-size types
pub trait ReadToBuffer {
    /// Read at most `max_count` instances of this atom type from the given
    /// stream, placing them into the supplied buffer.
    fn read_to_buffer<R>(r: &mut R, dest: &mut [u8], max_count: usize) -> io::Result<usize>
        where R: io::Read;
}

/// Possible results from `SizedRead::read_size`
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ReadSize {
    /// Exact size is known in advance
    Exact(usize),

    /// Size can be within the given range of values.
    Range(usize, usize)
}

impl ReadSize {
    /// Get the minimum number of bytes specified by this ReadSize.
    #[inline]
    fn min(&self) -> usize {
        match self {
            &ReadSize::Exact(s) => s,
            &ReadSize::Range(a, _) => a,
        }
    }
    /// Get the maximum number of bytes specified by this ReadSize.
    #[inline]
    fn max(&self) -> usize {
        match self {
            &ReadSize::Exact(s) => s,
            &ReadSize::Range(_, b) => b,
        }
    }

}

impl iter::Sum<ReadSize> for ReadSize {
    #[inline]
    fn sum<I>(iter: I) -> Self where I: Iterator<Item=ReadSize> {
        let mut sum = ReadSize::Exact(0);
        for rs in iter {
            sum += rs;
        }
        sum
    }
}

impl Add<ReadSize> for ReadSize {
    type Output = ReadSize;
    #[inline]
    fn add(self, rhs: ReadSize) -> Self::Output {
        let min = self.min() + rhs.min();
        let max = self.max() + rhs.max();
        if min == max { ReadSize::Exact(min) }
        else { ReadSize::Range(min, max) }
    }
}

impl AddAssign<ReadSize> for ReadSize {
    #[inline]
    fn add_assign(&mut self, rhs: ReadSize) {
        *self = *self + rhs;
    }
}

impl From<usize> for ReadSize {
    #[inline]
    fn from(s: usize) -> Self {
        ReadSize::Exact(s)
    }
}

impl From<Range<usize>> for ReadSize {
    #[inline]
    fn from(r: Range<usize>) -> Self {
        if r.len() > 1 { ReadSize::Range(r.start, r.end - 1) }
        else { ReadSize::Exact(r.start) }
    }
}

// ----------------------------------------------------------------
// Implementations

impl<'a> Bytes<'a> for u8 {
    type Iter = iter::Once<u8>;
    fn bytes(&self) -> Self::Iter {
        iter::once(*self)
    }
}

impl SizedRead for u8 {
    #[inline(always)]
    fn read_size(&self) -> ReadSize {
        ReadSize::Exact(1)
    }
}

impl ReadToBuffer for u8 {
    #[inline(always)]
    fn read_to_buffer<R>(r: &mut R, dest: &mut [u8], max_count: usize) -> io::Result<usize>
        where R: io::Read {
        r.read(&mut dest[0..max_count])
    }
}

// This table was copied from the Rust source tree,
// file "src/libcore/str/mod.rs".
// https://tools.ietf.org/html/rfc3629
static UTF8_CHAR_WIDTH: [u8; 256] = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF
0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF
4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF
];

impl<'a> Bytes<'a> for char {
    type Iter = char::EncodeUtf8;
    fn bytes(&self) -> Self::Iter {
        self.encode_utf8()
    }
}

impl SizedRead for char {
    #[inline]
    fn read_size(&self) -> ReadSize {
        self.len_utf8().into()
    }
}

impl ReadToBuffer for char {
    #[inline]
    fn read_to_buffer<R>(r: &mut R, dest: &mut [u8], max_count: usize) -> io::Result<usize>
        where R: io::Read {
        let mut i = 0;
        let mut n = 0;
        while i < dest.len() && n < max_count {
            try!(r.read_exact(&mut dest[i..(i+1)]));
            let w = UTF8_CHAR_WIDTH[dest[i] as usize];
            try!(r.read_exact(&mut dest[(i+1)..(i + w as usize)]));
            i += w as usize;
            n += 1;
        }
        Ok(i)
    }

}

#[cfg(test)]
#[test]
fn test_sizedread_char() {
    assert_eq!(ReadSize::Exact(1), 'a'.read_size());
    assert_eq!(ReadSize::Exact(3), '✓'.read_size());
}

#[cfg(test)]
#[test]
fn test_readable_char() {
    let mut buf = ['\0' as u8; 32];
    {
        let mut r = io::repeat('a' as u8);
        assert_eq!(3, char::read_to_buffer(&mut r, &mut buf, 3).unwrap());
        assert_eq!(&['a' as u8 as u8, 'a' as u8, 'a' as u8, '\0' as u8], &buf[0..4]);
    }

    {
        let s = "✓☠⚔";
        let mut r = io::Cursor::new(s.as_bytes());
        assert_eq!(9, char::read_to_buffer(&mut r, &mut buf, 3).unwrap());
        assert_eq!(s.as_bytes(), &buf[0..9]);
    }
}

// ----------------------------------------------------------------

/*impl<T> SizedRead for Transition<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        match self {
            &Transition::Atom(a) => a.read_size(),
            &Transition::Literal(ref atoms) => atoms.iter().map(|a| a.read_size()).sum(),
            &Transition::Wildcard => ReadSize::Range(1, 4),
            &Transition::Anchor(..) => ReadSize::Exact(0),
            &Transition::Class(ref c) => c.read_size(),
        }
    }
}*/

#[cfg(test)]
#[test]
fn test_sizedread_transition() {
    assert_eq!(ReadSize::Exact(1), 'a'.read_size());
    assert_eq!(ReadSize::Exact(3), '✓'.read_size());
    assert_eq!(ReadSize::Range(1, 3), Class::from_iter(['x', 'y', '⚔'].into_iter().cloned()).read_size());
}

// ----------------------------------------------------------------

impl<T> SizedRead for ClassMember<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        match self {
            &ClassMember::Atom(a) => a.read_size(),
            &ClassMember::Range(first, last) => {
                // We'll assume that any differences in read size between
                // `first` and `last` follow a linear function between the two;
                // this _assumption_ allows us to avoid evaluating `read_size`
                // for every single member of the range.
                let frs = first.read_size();
                let lrs = last.read_size();
                (cmp::min(frs.min(), lrs.min())..(cmp::max(frs.max(), lrs.max()) + 1)).into()
            }
        }
    }
}

impl<T> SizedRead for Class<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        let mut min = usize::MAX;
        let mut max = usize::MIN;

        for m in self.iter_members() {
            let rs = m.read_size();
            min = cmp::min(min, rs.min());
            max = cmp::max(max, rs.max());
        }

        (min..(max + 1)).into()
    }
}

<|endoftext|>


<commit_before>// This module implements simple request and response objects.
// Copyright (c) 2014 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use core;
use std::iter;
use std::ascii::OwnedAsciiExt;

use http::status;

/// Headers iterator.
pub type HeaderEntries<'a> = iter::Map<'static, &'a(String, String), (&'a String, &'a String), core::slice::Items<'a, (String, String)>>;
/// Header keys iterator.
pub type HeaderKeys<'a> = iter::Map<'static, (&'a String, &'a String), &'a String, HeaderEntries<'a>>;
/// Header values iterator.
pub type HeaderValues<'a> = iter::Map<'static, (&'a String, &'a String), &'a String, HeaderEntries<'a>>;

/// Headers type that stores some headers.  It has a HashMap like interface
/// but is ordered and can store the same keys multiple times.
pub struct Headers {
    list: Vec<(String, String)>,
}

impl Headers {
    /// Create `Headers`.
    pub fn new(list: Option<Vec<(String, String)>>) -> Headers {
        match list {
            Some(list) => Headers{list: list},
            None => Headers{list: Vec::new()},
        }
    }

    /// Return a reference to the value corresponding to the header key.
    pub fn get(&self, key: String) -> Option<&String> {
        let ikey = key.into_ascii_lower();
        for ref kvpairs in self.list.iter() {
            let k = kvpairs.ref0();
            let v = kvpairs.ref1();
            if k.clone().into_ascii_lower() == ikey {
                return Some(v)
            }
        }
        return None
    }

    /// Return a list of all the references to the values for a given key.
    /// If that key is not in the headers, the return value will be an empty vector.
    pub fn get_all(&self, key: String) -> Vec<&String> {
        let ikey = key.into_ascii_lower();
        let mut result = Vec::new();
        for ref kvpairs in self.list.iter() {
            let k = kvpairs.ref0();
            let v = kvpairs.ref1();
            if k.clone().into_ascii_lower() == ikey {
                result.push(v);
            }
        }
        return result
    }

    /// An iterator visiting all key-value pairs in sorted order.
    /// Iterator element type is `(&'a String, &'a String)`.
    pub fn iter(&self) -> HeaderEntries {
        self.list.iter().map(|ref kvpairs| (kvpairs.ref0(), kvpairs.ref1()))
    }

    /// An iterator visiting all keys in sorted order.
    /// Iterator element type is `&'a String`.
    pub fn keys(&self) -> HeaderKeys {
        self.iter().map(|(k, _v)| k)
    }

    /// An iterator visiting all values in sorted order.
    /// Iterator element type is `&'a String`.
    pub fn values(&self) -> HeaderValues {
        self.iter().map(|(_k, v)| v)
    }
}

/// Response type.  It is just one container with a couple of parameters
/// (headers, body, status code etc).
pub struct Response {
    pub status: status::Status,
    pub headers: Headers,
    pub body: String,
}

impl Response {
    /// Create a `Response`.
    pub fn new(body: String) -> Response {
        Response {
            status: status::Ok,
            headers: Headers::new(None),
            body: body,
        }
    }

    pub fn get_status_code(&self) -> u16 {
        self.status.code()
    }

    pub fn set_status_code(&mut self, code: u16) {
        match FromPrimitive::from_u64(code as u64) {
            Some(status) => { self.status = status; },
            None => { self.status = status::UnregisteredStatus(code as u16, String::from_str("UNKNOWN")); },
        }
    }

    pub fn get_status(&self) -> status::Status {
        self.status.clone()
    }

    pub fn set_status(&mut self, status: status::Status) {
        self.status = status;
    }
}
<commit_msg>Added headers clear<commit_after>// This module implements simple request and response objects.
// Copyright (c) 2014 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use core;
use std::iter;
use std::ascii::OwnedAsciiExt;

use http::status;

/// Headers iterator.
pub type HeaderEntries<'a> = iter::Map<'static, &'a(String, String), (&'a String, &'a String), core::slice::Items<'a, (String, String)>>;
/// Header keys iterator.
pub type HeaderKeys<'a> = iter::Map<'static, (&'a String, &'a String), &'a String, HeaderEntries<'a>>;
/// Header values iterator.
pub type HeaderValues<'a> = iter::Map<'static, (&'a String, &'a String), &'a String, HeaderEntries<'a>>;

/// Headers type that stores some headers.  It has a HashMap like interface
/// but is ordered and can store the same keys multiple times.
pub struct Headers {
    list: Vec<(String, String)>,
}

impl Headers {
    /// Create `Headers`.
    pub fn new(list: Option<Vec<(String, String)>>) -> Headers {
        match list {
            Some(list) => Headers{list: list},
            None => Headers{list: Vec::new()},
        }
    }

    /// Return a reference to the value corresponding to the header key.
    pub fn get(&self, key: String) -> Option<&String> {
        let ikey = key.into_ascii_lower();
        for ref kvpairs in self.list.iter() {
            let k = kvpairs.ref0();
            let v = kvpairs.ref1();
            if k.clone().into_ascii_lower() == ikey {
                return Some(v)
            }
        }
        return None
    }

    /// Return a list of all the references to the values for a given key.
    /// If that key is not in the headers, the return value will be an empty vector.
    pub fn get_all(&self, key: String) -> Vec<&String> {
        let ikey = key.into_ascii_lower();
        let mut result = Vec::new();
        for ref kvpairs in self.list.iter() {
            let k = kvpairs.ref0();
            let v = kvpairs.ref1();
            if k.clone().into_ascii_lower() == ikey {
                result.push(v);
            }
        }
        return result
    }

    /// An iterator visiting all key-value pairs in sorted order.
    /// Iterator element type is `(&'a String, &'a String)`.
    pub fn iter(&self) -> HeaderEntries {
        self.list.iter().map(|ref kvpairs| (kvpairs.ref0(), kvpairs.ref1()))
    }

    /// An iterator visiting all keys in sorted order.
    /// Iterator element type is `&'a String`.
    pub fn keys(&self) -> HeaderKeys {
        self.iter().map(|(k, _v)| k)
    }

    /// An iterator visiting all values in sorted order.
    /// Iterator element type is `&'a String`.
    pub fn values(&self) -> HeaderValues {
        self.iter().map(|(_k, v)| v)
    }

    /// Add a new header key-value pair to headers.
    /// TODO: _options_header_vkw
    pub fn add(&mut self, key: String, value: String) {
        self.list.push((key, value));
    }

    /// Return ths number of elements in the headers.
    pub fn len(&self) -> uint {
        return self.list.len();
    }

    /// Clears all headers.
    pub fn clear(&mut self) {
        self.list.clear();
    }
}

/// Response type.  It is just one container with a couple of parameters
/// (headers, body, status code etc).
pub struct Response {
    pub status: status::Status,
    pub headers: Headers,
    pub body: String,
}

impl Response {
    /// Create a `Response`.
    pub fn new(body: String) -> Response {
        Response {
            status: status::Ok,
            headers: Headers::new(None),
            body: body,
        }
    }

    pub fn get_status_code(&self) -> u16 {
        self.status.code()
    }

    pub fn set_status_code(&mut self, code: u16) {
        match FromPrimitive::from_u64(code as u64) {
            Some(status) => { self.status = status; },
            None => { self.status = status::UnregisteredStatus(code as u16, String::from_str("UNKNOWN")); },
        }
    }

    pub fn get_status(&self) -> status::Status {
        self.status.clone()
    }

    pub fn set_status(&mut self, status: status::Status) {
        self.status = status;
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
#![feature(globs)]
#![feature(managed_boxes)]
#![allow(non_camel_case_types)]

extern crate protobuf;
extern crate sync;

use std::io;
use std::io::Reader;
use std::io::Writer;
use std::str;
use plugin::*;
use protobuf::parse_from_reader;
use protobuf::Message;
use protobuf::codegen::*;

mod descriptor {
    pub use protobuf::descriptor::*;
}

mod plugin;

fn main() {
    let req = parse_from_reader::<CodeGeneratorRequest>(&mut io::stdio::stdin() as &mut Reader);
    let gen_options = GenOptions {
        dummy: false,
    };
    let result = gen(req.get_proto_file(), &gen_options);
    let mut resp = CodeGeneratorResponse::new();
    resp.set_file(result.iter().map(|file| {
        let mut r = CodeGeneratorResponse_File::new();
        r.set_name(file.name.to_string());
        r.set_content(str::from_utf8(file.content.as_slice()).unwrap().to_string());
        r
    }).collect());
    resp.write_to_writer(&mut io::stdout() as &mut Writer);
}
<commit_msg>We don't use managed boxes anymore<commit_after>#![crate_type = "bin"]
#![feature(globs)]
#![allow(non_camel_case_types)]

extern crate protobuf;
extern crate sync;

use std::io;
use std::io::Reader;
use std::io::Writer;
use std::str;
use plugin::*;
use protobuf::parse_from_reader;
use protobuf::Message;
use protobuf::codegen::*;

mod descriptor {
    pub use protobuf::descriptor::*;
}

mod plugin;

fn main() {
    let req = parse_from_reader::<CodeGeneratorRequest>(&mut io::stdio::stdin() as &mut Reader);
    let gen_options = GenOptions {
        dummy: false,
    };
    let result = gen(req.get_proto_file(), &gen_options);
    let mut resp = CodeGeneratorResponse::new();
    resp.set_file(result.iter().map(|file| {
        let mut r = CodeGeneratorResponse_File::new();
        r.set_name(file.name.to_string());
        r.set_content(str::from_utf8(file.content.as_slice()).unwrap().to_string());
        r
    }).collect());
    resp.write_to_writer(&mut io::stdout() as &mut Writer);
}
<|endoftext|>


<commit_before>use crate::colors::{BitDepth, ColorType};
use crate::headers::IhdrData;
use crate::png::PngImage;
use indexmap::IndexMap;
use itertools::Itertools;
use rgb::{FromSlice, RGB8, RGBA8};
use std::hash::Hash;

#[must_use]
pub fn reduce_rgba_to_grayscale_alpha(png: &PngImage) -> Option<PngImage> {
    let mut reduced = Vec::with_capacity(png.data.len());
    let byte_depth = png.ihdr.bit_depth.as_u8() >> 3;
    let bpp = 4 * byte_depth;
    let bpp_mask = bpp - 1;
    if 0 != bpp & bpp_mask {
        return None;
    }
    let colored_bytes = bpp - byte_depth;
    for line in png.scan_lines() {
        reduced.push(line.filter);
        let mut low_bytes = Vec::with_capacity(4);
        let mut high_bytes = Vec::with_capacity(4);
        let mut trans_bytes = Vec::with_capacity(byte_depth as usize);
        for (i, byte) in line.data.iter().enumerate() {
            if i as u8 & bpp_mask < colored_bytes {
                if byte_depth == 1 || i % 2 == 1 {
                    low_bytes.push(*byte);
                } else {
                    high_bytes.push(*byte);
                }
            } else {
                trans_bytes.push(*byte);
            }

            if (i as u8 & bpp_mask) == bpp - 1 {
                if low_bytes.iter().unique().count() > 1 {
                    return None;
                }
                if byte_depth == 2 {
                    if high_bytes.iter().unique().count() > 1 {
                        return None;
                    }
                    reduced.push(high_bytes[0]);
                    high_bytes.clear();
                }
                reduced.push(low_bytes[0]);
                low_bytes.clear();
                reduced.extend_from_slice(&trans_bytes);
                trans_bytes.clear();
            }
        }
    }

    let mut aux_headers = png.aux_headers.clone();
    if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
        if let Some(&s) = sbit_header.get(0) {
            aux_headers.insert(*b"sBIT", vec![s]);
        }
    }

    if let Some(bkgd_header) = png.aux_headers.get(b"bKGD") {
        if let Some(b) = bkgd_header.get(0..2) {
            aux_headers.insert(*b"bKGD", b.to_owned());
        }
    }

    Some(PngImage {
        data: reduced,
        ihdr: IhdrData {
            color_type: ColorType::GrayscaleAlpha,
            ..png.ihdr
        },
        palette: None,
        transparency_pixel: None,
        aux_headers,
    })
}

fn reduce_scanline_to_palette<T>(
    iter: impl IntoIterator<Item = T>,
    palette: &mut IndexMap<T, u8>,
    reduced: &mut Vec<u8>,
) -> bool
where
    T: Eq + Hash,
{
    for pixel in iter {
        let idx = if let Some(&idx) = palette.get(&pixel) {
            idx
        } else {
            let len = palette.len();
            if len == 256 {
                return false;
            }
            let idx = len as u8;
            palette.insert(pixel, idx);
            idx
        };
        reduced.push(idx);
    }
    true
}

#[must_use]
pub fn reduced_color_to_palette(png: &PngImage) -> Option<PngImage> {
    if png.ihdr.bit_depth != BitDepth::Eight {
        return None;
    }
    let mut raw_data = Vec::with_capacity(png.data.len());
    let mut palette = IndexMap::with_capacity(257);
    let transparency_pixel = png
        .transparency_pixel
        .as_ref()
        .map(|t| RGB8::new(t[1], t[3], t[5]));
    for line in png.scan_lines() {
        raw_data.push(line.filter);
        let ok = if png.ihdr.color_type == ColorType::RGB {
            reduce_scanline_to_palette(
                line.data.as_rgb().iter().cloned().map(|px| {
                    px.alpha(if Some(px) != transparency_pixel {
                        255
                    } else {
                        0
                    })
                }),
                &mut palette,
                &mut raw_data,
            )
        } else {
            debug_assert_eq!(png.ihdr.color_type, ColorType::RGBA);
            reduce_scanline_to_palette(
                line.data.as_rgba().iter().cloned(),
                &mut palette,
                &mut raw_data,
            )
        };
        if !ok {
            return None;
        }
    }

    let num_transparent = palette
        .iter()
        .filter_map(|(px, &idx)| {
            if px.a != 255 {
                Some(idx as usize + 1)
            } else {
                None
            }
        })
        .max();
    let trns_size = num_transparent.map(|n| n + 8).unwrap_or(0);

    let headers_size = palette.len() * 3 + 8 + trns_size;
    if raw_data.len() + headers_size > png.data.len() {
        // Reduction would result in a larger image
        return None;
    }

    let mut aux_headers = png.aux_headers.clone();
    if let Some(bkgd_header) = png.aux_headers.get(b"bKGD") {
        if bkgd_header.len() != 6 {
            // malformed chunk?
            return None;
        }
        // In bKGD 16-bit values are used even for 8-bit images
        let bg = RGBA8::new(bkgd_header[1], bkgd_header[3], bkgd_header[5], 255);
        let entry = if let Some(&entry) = palette.get(&bg) {
            entry
        } else if palette.len() < 256 {
            let entry = palette.len() as u8;
            palette.insert(bg, entry);
            entry
        } else {
            return None; // No space in palette to store the bg as an index
        };
        aux_headers.insert(*b"bKGD", vec![entry]);
    }

    if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
        // Some programs save the sBIT header as RGB even if the image is RGBA.
        aux_headers.insert(*b"sBIT", sbit_header.iter().cloned().take(3).collect());
    }

    let mut palette_vec = vec![RGBA8::new(0, 0, 0, 0); palette.len()];
    for (color, idx) in palette {
        palette_vec[idx as usize] = color;
    }

    Some(PngImage {
        data: raw_data,
        ihdr: IhdrData {
            color_type: ColorType::Indexed,
            ..png.ihdr
        },
        aux_headers,
        transparency_pixel: None,
        palette: Some(palette_vec),
    })
}

#[must_use]
pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option<PngImage> {
    let mut reduced = Vec::with_capacity(png.data.len());
    let byte_depth: u8 = png.ihdr.bit_depth.as_u8() >> 3;
    let bpp: usize = 3 * byte_depth as usize;
    let mut cur_pixel = Vec::with_capacity(bpp);
    for line in png.scan_lines() {
        reduced.push(line.filter);
        for (i, byte) in line.data.iter().enumerate() {
            cur_pixel.push(*byte);
            if i % bpp == bpp - 1 {
                if bpp == 3 {
                    if cur_pixel.iter().unique().count() > 1 {
                        return None;
                    }
                    reduced.push(cur_pixel[0]);
                } else {
                    let pixel_bytes = cur_pixel
                        .iter()
                        .step_by(2)
                        .cloned()
                        .zip(cur_pixel.iter().skip(1).step_by(2).cloned())
                        .unique()
                        .collect::<Vec<(u8, u8)>>();
                    if pixel_bytes.len() > 1 {
                        return None;
                    }
                    reduced.push(pixel_bytes[0].0);
                    reduced.push(pixel_bytes[0].1);
                }
                cur_pixel.clear();
            }
        }
    }

    let transparency_pixel = if let Some(ref trns) = png.transparency_pixel {
        if trns.len() != 6 || trns[0..2] != trns[2..4] || trns[2..4] != trns[4..6] {
            None
        } else {
            Some(trns[0..2].to_owned())
        }
    } else {
        png.transparency_pixel.clone()
    };

    let mut aux_headers = png.aux_headers.clone();
    if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
        if let Some(&byte) = sbit_header.get(0) {
            aux_headers.insert(*b"sBIT", vec![byte]);
        }
    }
    if let Some(bkgd_header) = png.aux_headers.get(b"bKGD") {
        if let Some(b) = bkgd_header.get(0..2) {
            aux_headers.insert(*b"bKGD", b.to_owned());
        }
    }

    Some(PngImage {
        data: reduced,
        ihdr: IhdrData {
            color_type: ColorType::Grayscale,
            ..png.ihdr
        },
        aux_headers,
        palette: None,
        transparency_pixel,
    })
}
<commit_msg>Ignore broken tRNS<commit_after>use crate::colors::{BitDepth, ColorType};
use crate::headers::IhdrData;
use crate::png::PngImage;
use indexmap::IndexMap;
use itertools::Itertools;
use rgb::{FromSlice, RGB8, RGBA8};
use std::hash::Hash;

#[must_use]
pub fn reduce_rgba_to_grayscale_alpha(png: &PngImage) -> Option<PngImage> {
    let mut reduced = Vec::with_capacity(png.data.len());
    let byte_depth = png.ihdr.bit_depth.as_u8() >> 3;
    let bpp = 4 * byte_depth;
    let bpp_mask = bpp - 1;
    if 0 != bpp & bpp_mask {
        return None;
    }
    let colored_bytes = bpp - byte_depth;
    for line in png.scan_lines() {
        reduced.push(line.filter);
        let mut low_bytes = Vec::with_capacity(4);
        let mut high_bytes = Vec::with_capacity(4);
        let mut trans_bytes = Vec::with_capacity(byte_depth as usize);
        for (i, byte) in line.data.iter().enumerate() {
            if i as u8 & bpp_mask < colored_bytes {
                if byte_depth == 1 || i % 2 == 1 {
                    low_bytes.push(*byte);
                } else {
                    high_bytes.push(*byte);
                }
            } else {
                trans_bytes.push(*byte);
            }

            if (i as u8 & bpp_mask) == bpp - 1 {
                if low_bytes.iter().unique().count() > 1 {
                    return None;
                }
                if byte_depth == 2 {
                    if high_bytes.iter().unique().count() > 1 {
                        return None;
                    }
                    reduced.push(high_bytes[0]);
                    high_bytes.clear();
                }
                reduced.push(low_bytes[0]);
                low_bytes.clear();
                reduced.extend_from_slice(&trans_bytes);
                trans_bytes.clear();
            }
        }
    }

    let mut aux_headers = png.aux_headers.clone();
    if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
        if let Some(&s) = sbit_header.get(0) {
            aux_headers.insert(*b"sBIT", vec![s]);
        }
    }

    if let Some(bkgd_header) = png.aux_headers.get(b"bKGD") {
        if let Some(b) = bkgd_header.get(0..2) {
            aux_headers.insert(*b"bKGD", b.to_owned());
        }
    }

    Some(PngImage {
        data: reduced,
        ihdr: IhdrData {
            color_type: ColorType::GrayscaleAlpha,
            ..png.ihdr
        },
        palette: None,
        transparency_pixel: None,
        aux_headers,
    })
}

fn reduce_scanline_to_palette<T>(
    iter: impl IntoIterator<Item = T>,
    palette: &mut IndexMap<T, u8>,
    reduced: &mut Vec<u8>,
) -> bool
where
    T: Eq + Hash,
{
    for pixel in iter {
        let idx = if let Some(&idx) = palette.get(&pixel) {
            idx
        } else {
            let len = palette.len();
            if len == 256 {
                return false;
            }
            let idx = len as u8;
            palette.insert(pixel, idx);
            idx
        };
        reduced.push(idx);
    }
    true
}

#[must_use]
pub fn reduced_color_to_palette(png: &PngImage) -> Option<PngImage> {
    if png.ihdr.bit_depth != BitDepth::Eight {
        return None;
    }
    let mut raw_data = Vec::with_capacity(png.data.len());
    let mut palette = IndexMap::with_capacity(257);
    let transparency_pixel = png
        .transparency_pixel
        .as_ref()
        .filter(|t| png.ihdr.color_type == ColorType::RGB && t.len() >= 6)
        .map(|t| RGB8::new(t[1], t[3], t[5]));
    for line in png.scan_lines() {
        raw_data.push(line.filter);
        let ok = if png.ihdr.color_type == ColorType::RGB {
            reduce_scanline_to_palette(
                line.data.as_rgb().iter().cloned().map(|px| {
                    px.alpha(if Some(px) != transparency_pixel {
                        255
                    } else {
                        0
                    })
                }),
                &mut palette,
                &mut raw_data,
            )
        } else {
            debug_assert_eq!(png.ihdr.color_type, ColorType::RGBA);
            reduce_scanline_to_palette(
                line.data.as_rgba().iter().cloned(),
                &mut palette,
                &mut raw_data,
            )
        };
        if !ok {
            return None;
        }
    }

    let num_transparent = palette
        .iter()
        .filter_map(|(px, &idx)| {
            if px.a != 255 {
                Some(idx as usize + 1)
            } else {
                None
            }
        })
        .max();
    let trns_size = num_transparent.map(|n| n + 8).unwrap_or(0);

    let headers_size = palette.len() * 3 + 8 + trns_size;
    if raw_data.len() + headers_size > png.data.len() {
        // Reduction would result in a larger image
        return None;
    }

    let mut aux_headers = png.aux_headers.clone();
    if let Some(bkgd_header) = png.aux_headers.get(b"bKGD") {
        if bkgd_header.len() != 6 {
            // malformed chunk?
            return None;
        }
        // In bKGD 16-bit values are used even for 8-bit images
        let bg = RGBA8::new(bkgd_header[1], bkgd_header[3], bkgd_header[5], 255);
        let entry = if let Some(&entry) = palette.get(&bg) {
            entry
        } else if palette.len() < 256 {
            let entry = palette.len() as u8;
            palette.insert(bg, entry);
            entry
        } else {
            return None; // No space in palette to store the bg as an index
        };
        aux_headers.insert(*b"bKGD", vec![entry]);
    }

    if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
        // Some programs save the sBIT header as RGB even if the image is RGBA.
        aux_headers.insert(*b"sBIT", sbit_header.iter().cloned().take(3).collect());
    }

    let mut palette_vec = vec![RGBA8::new(0, 0, 0, 0); palette.len()];
    for (color, idx) in palette {
        palette_vec[idx as usize] = color;
    }

    Some(PngImage {
        data: raw_data,
        ihdr: IhdrData {
            color_type: ColorType::Indexed,
            ..png.ihdr
        },
        aux_headers,
        transparency_pixel: None,
        palette: Some(palette_vec),
    })
}

#[must_use]
pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option<PngImage> {
    let mut reduced = Vec::with_capacity(png.data.len());
    let byte_depth: u8 = png.ihdr.bit_depth.as_u8() >> 3;
    let bpp: usize = 3 * byte_depth as usize;
    let mut cur_pixel = Vec::with_capacity(bpp);
    for line in png.scan_lines() {
        reduced.push(line.filter);
        for (i, byte) in line.data.iter().enumerate() {
            cur_pixel.push(*byte);
            if i % bpp == bpp - 1 {
                if bpp == 3 {
                    if cur_pixel.iter().unique().count() > 1 {
                        return None;
                    }
                    reduced.push(cur_pixel[0]);
                } else {
                    let pixel_bytes = cur_pixel
                        .iter()
                        .step_by(2)
                        .cloned()
                        .zip(cur_pixel.iter().skip(1).step_by(2).cloned())
                        .unique()
                        .collect::<Vec<(u8, u8)>>();
                    if pixel_bytes.len() > 1 {
                        return None;
                    }
                    reduced.push(pixel_bytes[0].0);
                    reduced.push(pixel_bytes[0].1);
                }
                cur_pixel.clear();
            }
        }
    }

    let transparency_pixel = if let Some(ref trns) = png.transparency_pixel {
        if trns.len() != 6 || trns[0..2] != trns[2..4] || trns[2..4] != trns[4..6] {
            None
        } else {
            Some(trns[0..2].to_owned())
        }
    } else {
        png.transparency_pixel.clone()
    };

    let mut aux_headers = png.aux_headers.clone();
    if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
        if let Some(&byte) = sbit_header.get(0) {
            aux_headers.insert(*b"sBIT", vec![byte]);
        }
    }
    if let Some(bkgd_header) = png.aux_headers.get(b"bKGD") {
        if let Some(b) = bkgd_header.get(0..2) {
            aux_headers.insert(*b"bKGD", b.to_owned());
        }
    }

    Some(PngImage {
        data: reduced,
        ihdr: IhdrData {
            color_type: ColorType::Grayscale,
            ..png.ihdr
        },
        aux_headers,
        palette: None,
        transparency_pixel,
    })
}
<|endoftext|>


<commit_before>use tcod::colors::{Color};

use traits::{Renderable, Movable, Position};
use point::Point;

#[derive(Debug)]
pub struct Item {
    name: String,
    glyph: char,
    color: Color,
    position: Point<i16>,
}

impl Item {
    pub fn new(name: &str, glyph: char, color: Color, pos: Point<i16>) -> Item {
        Item {
            name: name.into(),
            glyph: glyph,
            color: color,
            position: pos,
        }
    }
}

impl Position for Item {
    fn get_x(&self) -> i16 {
        self.position.x
    }

    fn get_y(&self) -> i16 {
        self.position.y
    }
}

impl Renderable for Item {
    fn get_color(&self) -> Color {
        self.color
    }

    fn get_glyph(&self) -> char {
        self.glyph
    }
}<commit_msg>Remove unused trait import.<commit_after>use tcod::colors::{Color};

use traits::{Renderable, Position};
use point::Point;

#[derive(Debug)]
pub struct Item {
    name: String,
    glyph: char,
    color: Color,
    position: Point<i16>,
}

impl Item {
    pub fn new(name: &str, glyph: char, color: Color, pos: Point<i16>) -> Item {
        Item {
            name: name.into(),
            glyph: glyph,
            color: color,
            position: pos,
        }
    }
}

impl Position for Item {
    fn get_x(&self) -> i16 {
        self.position.x
    }

    fn get_y(&self) -> i16 {
        self.position.y
    }
}

impl Renderable for Item {
    fn get_color(&self) -> Color {
        self.color
    }

    fn get_glyph(&self) -> char {
        self.glyph
    }
}<|endoftext|>