<commit_before>use std::fmt;
use std::rc::Rc;
use std::str::FromStr;

use semver::VersionReq;
use semver::ReqParseError;
use rustc_serialize::{Encoder, Encodable};

use core::{SourceId, Summary, PackageId};
use util::{CargoError, CargoResult, Cfg, CfgExpr, ChainError, human, Config};

/// Information about a dependency requested by a Cargo manifest.
/// Cheap to copy.
#[derive(PartialEq, Clone ,Debug)]
pub struct Dependency {
    inner: Rc<DependencyInner>,
}

/// The data underlying a Dependency.
#[derive(PartialEq, Clone, Debug)]
pub struct DependencyInner {
    name: String,
    source_id: SourceId,
    req: VersionReq,
    specified_req: bool,
    kind: Kind,
    only_match_name: bool,

    optional: bool,
    default_features: bool,
    features: Vec<String>,

    // This dependency should be used only for this platform.
    // `None` means *all platforms*.
    platform: Option<Platform>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Platform {
    Name(String),
    Cfg(CfgExpr),
}

#[derive(RustcEncodable)]
struct SerializedDependency<'a> {
    name: &'a str,
    source: &'a SourceId,
    req: String,
    kind: Kind,

    optional: bool,
    uses_default_features: bool,
    features: &'a [String],
    target: Option<&'a Platform>,
}

impl Encodable for Dependency {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        SerializedDependency {
            name: self.name(),
            source: &self.source_id(),
            req: self.version_req().to_string(),
            kind: self.kind(),
            optional: self.is_optional(),
            uses_default_features: self.uses_default_features(),
            features: self.features(),
            target: self.platform(),
        }.encode(s)
    }
}

#[derive(PartialEq, Clone, Debug, Copy)]
pub enum Kind {
    Normal,
    Development,
    Build,
}

impl Encodable for Kind {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Kind::Normal => None,
            Kind::Development => Some("dev"),
            Kind::Build => Some("build"),
        }.encode(s)
    }
}

impl DependencyInner {
    /// Attempt to create a `Dependency` from an entry in the manifest.
    pub fn parse(name: &str,
                 version: Option<&str>,
                 source_id: &SourceId,
                 _config: &Config) -> CargoResult<DependencyInner> {
        let (specified_req, version_req) = match version {
            Some(v) => (true, try!(DependencyInner::parse_with_deprecated(v))),
            None => (false, VersionReq::any())
        };

        Ok(DependencyInner {
            only_match_name: false,
            req: version_req,
            specified_req: specified_req,
            .. DependencyInner::new_override(name, source_id)
        })
    }

    fn parse_with_deprecated(req: &str) -> Result<VersionReq, ReqParseError> {
        match VersionReq::parse(req) {
            Err(e) => {
                match e {
                    ReqParseError::DeprecatedVersionRequirement(requirement) => {
                        // warn here

                        Ok(requirement)
                    }
                    e => Err(e),
                }
            },
            Ok(v) => Ok(v),
        }
    }

    pub fn new_override(name: &str, source_id: &SourceId) -> DependencyInner {
        DependencyInner {
            name: name.to_string(),
            source_id: source_id.clone(),
            req: VersionReq::any(),
            kind: Kind::Normal,
            only_match_name: true,
            optional: false,
            features: Vec::new(),
            default_features: true,
            specified_req: false,
            platform: None,
        }
    }

    pub fn version_req(&self) -> &VersionReq { &self.req }
    pub fn name(&self) -> &str { &self.name }
    pub fn source_id(&self) -> &SourceId { &self.source_id }
    pub fn kind(&self) -> Kind { self.kind }
    pub fn specified_req(&self) -> bool { self.specified_req }

    /// If none, this dependency must be built for all platforms.
    /// If some, it must only be built for matching platforms.
    pub fn platform(&self) -> Option<&Platform> {
        self.platform.as_ref()
    }

    pub fn set_kind(mut self, kind: Kind) -> DependencyInner {
        self.kind = kind;
        self
    }

    /// Sets the list of features requested for the package.
    pub fn set_features(mut self, features: Vec<String>) -> DependencyInner {
        self.features = features;
        self
    }

    /// Sets whether the dependency requests default features of the package.
    pub fn set_default_features(mut self, default_features: bool) -> DependencyInner {
        self.default_features = default_features;
        self
    }

    /// Sets whether the dependency is optional.
    pub fn set_optional(mut self, optional: bool) -> DependencyInner {
        self.optional = optional;
        self
    }

    /// Set the source id for this dependency
    pub fn set_source_id(mut self, id: SourceId) -> DependencyInner {
        self.source_id = id;
        self
    }

    /// Set the version requirement for this dependency
    pub fn set_version_req(mut self, req: VersionReq) -> DependencyInner {
        self.req = req;
        self
    }

    pub fn set_platform(mut self, platform: Option<Platform>)
                        -> DependencyInner {
        self.platform = platform;
        self
    }

    /// Lock this dependency to depending on the specified package id
    pub fn lock_to(self, id: &PackageId) -> DependencyInner {
        assert_eq!(self.source_id, *id.source_id());
        assert!(self.req.matches(id.version()));
        self.set_version_req(VersionReq::exact(id.version()))
            .set_source_id(id.source_id().clone())
    }

    /// Returns false if the dependency is only used to build the local package.
    pub fn is_transitive(&self) -> bool {
        match self.kind {
            Kind::Normal | Kind::Build => true,
            Kind::Development => false,
        }
    }
    pub fn is_build(&self) -> bool {
        match self.kind { Kind::Build => true, _ => false }
    }
    pub fn is_optional(&self) -> bool { self.optional }
    /// Returns true if the default features of the dependency are requested.
    pub fn uses_default_features(&self) -> bool { self.default_features }
    /// Returns the list of features that are requested by the dependency.
    pub fn features(&self) -> &[String] { &self.features }

    /// Returns true if the package (`sum`) can fulfill this dependency request.
    pub fn matches(&self, sum: &Summary) -> bool {
        self.matches_id(sum.package_id())
    }

    /// Returns true if the package (`id`) can fulfill this dependency request.
    pub fn matches_id(&self, id: &PackageId) -> bool {
        self.name == id.name() &&
            (self.only_match_name || (self.req.matches(id.version()) &&
                                      &self.source_id == id.source_id()))
    }

    pub fn into_dependency(self) -> Dependency {
        Dependency {inner: Rc::new(self)}
    }
}

impl Dependency {
    /// Attempt to create a `Dependency` from an entry in the manifest.
    pub fn parse(name: &str,
                 version: Option<&str>,
                 source_id: &SourceId,
                 config: &Config) -> CargoResult<Dependency> {
        DependencyInner::parse(name, version, source_id, config).map(|di| {
            di.into_dependency()
        })
    }

    pub fn new_override(name: &str, source_id: &SourceId) -> Dependency {
        DependencyInner::new_override(name, source_id).into_dependency()
    }

    pub fn clone_inner(&self) -> DependencyInner { (*self.inner).clone() }

    pub fn version_req(&self) -> &VersionReq { self.inner.version_req() }
    pub fn name(&self) -> &str { self.inner.name() }
    pub fn source_id(&self) -> &SourceId { self.inner.source_id() }
    pub fn kind(&self) -> Kind { self.inner.kind() }
    pub fn specified_req(&self) -> bool { self.inner.specified_req() }

    /// If none, this dependencies must be built for all platforms.
    /// If some, it must only be built for the specified platform.
    pub fn platform(&self) -> Option<&Platform> {
        self.inner.platform()
    }

    /// Lock this dependency to depending on the specified package id
    pub fn lock_to(self, id: &PackageId) -> Dependency {
        self.clone_inner().lock_to(id).into_dependency()
    }

    /// Returns false if the dependency is only used to build the local package.
    pub fn is_transitive(&self) -> bool { self.inner.is_transitive() }
    pub fn is_build(&self) -> bool { self.inner.is_build() }
    pub fn is_optional(&self) -> bool { self.inner.is_optional() }

    /// Returns true if the default features of the dependency are requested.
    pub fn uses_default_features(&self) -> bool {
        self.inner.uses_default_features()
    }
    /// Returns the list of features that are requested by the dependency.
    pub fn features(&self) -> &[String] { self.inner.features() }

    /// Returns true if the package (`sum`) can fulfill this dependency request.
    pub fn matches(&self, sum: &Summary) -> bool { self.inner.matches(sum) }

    /// Returns true if the package (`id`) can fulfill this dependency request.
    pub fn matches_id(&self, id: &PackageId) -> bool {
        self.inner.matches_id(id)
    }

    pub fn map_source(self, to_replace: &SourceId, replace_with: &SourceId)
                      -> Dependency {
        if self.source_id() != to_replace {
            self
        } else {
            Rc::try_unwrap(self.inner).unwrap_or_else(|r| (*r).clone())
               .set_source_id(replace_with.clone())
               .into_dependency()
        }
    }
}

impl Platform {
    pub fn matches(&self, name: &str, cfg: Option<&[Cfg]>) -> bool {
        match *self {
            Platform::Name(ref p) => p == name,
            Platform::Cfg(ref p) => {
                match cfg {
                    Some(cfg) => p.matches(cfg),
                    None => false,
                }
            }
        }
    }
}

impl Encodable for Platform {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.to_string().encode(s)
    }
}

impl FromStr for Platform {
    type Err = Box<CargoError>;

    fn from_str(s: &str) -> CargoResult<Platform> {
        if s.starts_with("cfg(") && s.ends_with(")") {
            let s = &s[4..s.len()-1];
            s.parse().map(Platform::Cfg).chain_error(|| {
                human(format!("failed to parse `{}` as a cfg expression", s))
            })
        } else {
            Ok(Platform::Name(s.to_string()))
        }
    }
}

impl fmt::Display for Platform {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Platform::Name(ref n) => n.fmt(f),
            Platform::Cfg(ref e) => write!(f, "cfg({})", e),
        }
    }
}
<commit_msg>Print the warning<commit_after>use std::fmt;
use std::rc::Rc;
use std::str::FromStr;

use semver::VersionReq;
use semver::ReqParseError;
use rustc_serialize::{Encoder, Encodable};

use core::{SourceId, Summary, PackageId};
use util::{CargoError, CargoResult, Cfg, CfgExpr, ChainError, human, Config};

/// Information about a dependency requested by a Cargo manifest.
/// Cheap to copy.
#[derive(PartialEq, Clone ,Debug)]
pub struct Dependency {
    inner: Rc<DependencyInner>,
}

/// The data underlying a Dependency.
#[derive(PartialEq, Clone, Debug)]
pub struct DependencyInner {
    name: String,
    source_id: SourceId,
    req: VersionReq,
    specified_req: bool,
    kind: Kind,
    only_match_name: bool,

    optional: bool,
    default_features: bool,
    features: Vec<String>,

    // This dependency should be used only for this platform.
    // `None` means *all platforms*.
    platform: Option<Platform>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Platform {
    Name(String),
    Cfg(CfgExpr),
}

#[derive(RustcEncodable)]
struct SerializedDependency<'a> {
    name: &'a str,
    source: &'a SourceId,
    req: String,
    kind: Kind,

    optional: bool,
    uses_default_features: bool,
    features: &'a [String],
    target: Option<&'a Platform>,
}

impl Encodable for Dependency {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        SerializedDependency {
            name: self.name(),
            source: &self.source_id(),
            req: self.version_req().to_string(),
            kind: self.kind(),
            optional: self.is_optional(),
            uses_default_features: self.uses_default_features(),
            features: self.features(),
            target: self.platform(),
        }.encode(s)
    }
}

#[derive(PartialEq, Clone, Debug, Copy)]
pub enum Kind {
    Normal,
    Development,
    Build,
}

impl Encodable for Kind {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Kind::Normal => None,
            Kind::Development => Some("dev"),
            Kind::Build => Some("build"),
        }.encode(s)
    }
}

impl DependencyInner {
    /// Attempt to create a `Dependency` from an entry in the manifest.
    pub fn parse(name: &str,
                 version: Option<&str>,
                 source_id: &SourceId,
                 config: &Config) -> CargoResult<DependencyInner> {
        let (specified_req, version_req) = match version {
            Some(v) => (true, try!(DependencyInner::parse_with_deprecated(v, config))),
            None => (false, VersionReq::any())
        };

        Ok(DependencyInner {
            only_match_name: false,
            req: version_req,
            specified_req: specified_req,
            .. DependencyInner::new_override(name, source_id)
        })
    }

    fn parse_with_deprecated(req: &str, config: &Config) -> CargoResult<VersionReq> {
        match VersionReq::parse(req) {
            Err(e) => {
                match e {
                    ReqParseError::DeprecatedVersionRequirement(requirement) => {
                        let msg = format!("One of your version requirements ({}) is invalid. \
Previous versions of Cargo accepted this malformed requirement, but it is being deprecated. Please \
use {} instead.", req, requirement);
                        try!(config.shell().warn(&msg));

                        Ok(requirement)
                    }
                    e => Err(From::from(e)),
                }
            },
            Ok(v) => Ok(v),
        }
    }

    pub fn new_override(name: &str, source_id: &SourceId) -> DependencyInner {
        DependencyInner {
            name: name.to_string(),
            source_id: source_id.clone(),
            req: VersionReq::any(),
            kind: Kind::Normal,
            only_match_name: true,
            optional: false,
            features: Vec::new(),
            default_features: true,
            specified_req: false,
            platform: None,
        }
    }

    pub fn version_req(&self) -> &VersionReq { &self.req }
    pub fn name(&self) -> &str { &self.name }
    pub fn source_id(&self) -> &SourceId { &self.source_id }
    pub fn kind(&self) -> Kind { self.kind }
    pub fn specified_req(&self) -> bool { self.specified_req }

    /// If none, this dependency must be built for all platforms.
    /// If some, it must only be built for matching platforms.
    pub fn platform(&self) -> Option<&Platform> {
        self.platform.as_ref()
    }

    pub fn set_kind(mut self, kind: Kind) -> DependencyInner {
        self.kind = kind;
        self
    }

    /// Sets the list of features requested for the package.
    pub fn set_features(mut self, features: Vec<String>) -> DependencyInner {
        self.features = features;
        self
    }

    /// Sets whether the dependency requests default features of the package.
    pub fn set_default_features(mut self, default_features: bool) -> DependencyInner {
        self.default_features = default_features;
        self
    }

    /// Sets whether the dependency is optional.
    pub fn set_optional(mut self, optional: bool) -> DependencyInner {
        self.optional = optional;
        self
    }

    /// Set the source id for this dependency
    pub fn set_source_id(mut self, id: SourceId) -> DependencyInner {
        self.source_id = id;
        self
    }

    /// Set the version requirement for this dependency
    pub fn set_version_req(mut self, req: VersionReq) -> DependencyInner {
        self.req = req;
        self
    }

    pub fn set_platform(mut self, platform: Option<Platform>)
                        -> DependencyInner {
        self.platform = platform;
        self
    }

    /// Lock this dependency to depending on the specified package id
    pub fn lock_to(self, id: &PackageId) -> DependencyInner {
        assert_eq!(self.source_id, *id.source_id());
        assert!(self.req.matches(id.version()));
        self.set_version_req(VersionReq::exact(id.version()))
            .set_source_id(id.source_id().clone())
    }

    /// Returns false if the dependency is only used to build the local package.
    pub fn is_transitive(&self) -> bool {
        match self.kind {
            Kind::Normal | Kind::Build => true,
            Kind::Development => false,
        }
    }
    pub fn is_build(&self) -> bool {
        match self.kind { Kind::Build => true, _ => false }
    }
    pub fn is_optional(&self) -> bool { self.optional }
    /// Returns true if the default features of the dependency are requested.
    pub fn uses_default_features(&self) -> bool { self.default_features }
    /// Returns the list of features that are requested by the dependency.
    pub fn features(&self) -> &[String] { &self.features }

    /// Returns true if the package (`sum`) can fulfill this dependency request.
    pub fn matches(&self, sum: &Summary) -> bool {
        self.matches_id(sum.package_id())
    }

    /// Returns true if the package (`id`) can fulfill this dependency request.
    pub fn matches_id(&self, id: &PackageId) -> bool {
        self.name == id.name() &&
            (self.only_match_name || (self.req.matches(id.version()) &&
                                      &self.source_id == id.source_id()))
    }

    pub fn into_dependency(self) -> Dependency {
        Dependency {inner: Rc::new(self)}
    }
}

impl Dependency {
    /// Attempt to create a `Dependency` from an entry in the manifest.
    pub fn parse(name: &str,
                 version: Option<&str>,
                 source_id: &SourceId,
                 config: &Config) -> CargoResult<Dependency> {
        DependencyInner::parse(name, version, source_id, config).map(|di| {
            di.into_dependency()
        })
    }

    pub fn new_override(name: &str, source_id: &SourceId) -> Dependency {
        DependencyInner::new_override(name, source_id).into_dependency()
    }

    pub fn clone_inner(&self) -> DependencyInner { (*self.inner).clone() }

    pub fn version_req(&self) -> &VersionReq { self.inner.version_req() }
    pub fn name(&self) -> &str { self.inner.name() }
    pub fn source_id(&self) -> &SourceId { self.inner.source_id() }
    pub fn kind(&self) -> Kind { self.inner.kind() }
    pub fn specified_req(&self) -> bool { self.inner.specified_req() }

    /// If none, this dependencies must be built for all platforms.
    /// If some, it must only be built for the specified platform.
    pub fn platform(&self) -> Option<&Platform> {
        self.inner.platform()
    }

    /// Lock this dependency to depending on the specified package id
    pub fn lock_to(self, id: &PackageId) -> Dependency {
        self.clone_inner().lock_to(id).into_dependency()
    }

    /// Returns false if the dependency is only used to build the local package.
    pub fn is_transitive(&self) -> bool { self.inner.is_transitive() }
    pub fn is_build(&self) -> bool { self.inner.is_build() }
    pub fn is_optional(&self) -> bool { self.inner.is_optional() }

    /// Returns true if the default features of the dependency are requested.
    pub fn uses_default_features(&self) -> bool {
        self.inner.uses_default_features()
    }
    /// Returns the list of features that are requested by the dependency.
    pub fn features(&self) -> &[String] { self.inner.features() }

    /// Returns true if the package (`sum`) can fulfill this dependency request.
    pub fn matches(&self, sum: &Summary) -> bool { self.inner.matches(sum) }

    /// Returns true if the package (`id`) can fulfill this dependency request.
    pub fn matches_id(&self, id: &PackageId) -> bool {
        self.inner.matches_id(id)
    }

    pub fn map_source(self, to_replace: &SourceId, replace_with: &SourceId)
                      -> Dependency {
        if self.source_id() != to_replace {
            self
        } else {
            Rc::try_unwrap(self.inner).unwrap_or_else(|r| (*r).clone())
               .set_source_id(replace_with.clone())
               .into_dependency()
        }
    }
}

impl Platform {
    pub fn matches(&self, name: &str, cfg: Option<&[Cfg]>) -> bool {
        match *self {
            Platform::Name(ref p) => p == name,
            Platform::Cfg(ref p) => {
                match cfg {
                    Some(cfg) => p.matches(cfg),
                    None => false,
                }
            }
        }
    }
}

impl Encodable for Platform {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.to_string().encode(s)
    }
}

impl FromStr for Platform {
    type Err = Box<CargoError>;

    fn from_str(s: &str) -> CargoResult<Platform> {
        if s.starts_with("cfg(") && s.ends_with(")") {
            let s = &s[4..s.len()-1];
            s.parse().map(Platform::Cfg).chain_error(|| {
                human(format!("failed to parse `{}` as a cfg expression", s))
            })
        } else {
            Ok(Platform::Name(s.to_string()))
        }
    }
}

impl fmt::Display for Platform {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Platform::Name(ref n) => n.fmt(f),
            Platform::Cfg(ref e) => write!(f, "cfg({})", e),
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::{HashMap, IterMut, Values};
use std::fmt;

use core::{Dependency, Package, PackageId, Summary};
use util::CargoResult;

mod source_id;

pub use self::source_id::{GitReference, SourceId};

/// A Source finds and downloads remote packages based on names and
/// versions.
pub trait Source {
    /// Returns the `SourceId` corresponding to this source
    fn source_id(&self) -> &SourceId;

    /// Returns the replaced `SourceId` corresponding to this source
    fn replaced_source_id(&self) -> &SourceId {
        self.source_id()
    }

    /// Returns whether or not this source will return summaries with
    /// checksums listed.
    fn supports_checksums(&self) -> bool;

    /// Returns whether or not this source will return summaries with
    /// the `precise` field in the source id listed.
    fn requires_precise(&self) -> bool;

    /// Attempt to find the packages that match a dependency request.
    fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()>;

    /// Attempt to find the packages that are close to a dependency request.
    /// Each source gets to define what `close` means for it.
    /// path/git sources may return all dependencies that are at that uri.
    /// where as an Index source may return dependencies that have the same canonicalization.
    fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()>;

    fn query_vec(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
        let mut ret = Vec::new();
        self.query(dep, &mut |s| ret.push(s))?;
        Ok(ret)
    }

    /// The update method performs any network operations required to
    /// get the entire list of all names, versions and dependencies of
    /// packages managed by the Source.
    fn update(&mut self) -> CargoResult<()>;

    /// The download method fetches the full package for each name and
    /// version specified.
    fn download(&mut self, package: &PackageId) -> CargoResult<MaybePackage>;

    fn finish_download(&mut self, package: &PackageId, contents: Vec<u8>) -> CargoResult<Package>;

    /// Generates a unique string which represents the fingerprint of the
    /// current state of the source.
    ///
    /// This fingerprint is used to determine the "fresheness" of the source
    /// later on. It must be guaranteed that the fingerprint of a source is
    /// constant if and only if the output product will remain constant.
    ///
    /// The `pkg` argument is the package which this fingerprint should only be
    /// interested in for when this source may contain multiple packages.
    fn fingerprint(&self, pkg: &Package) -> CargoResult<String>;

    /// If this source supports it, verifies the source of the package
    /// specified.
    ///
    /// Note that the source may also have performed other checksum-based
    /// verification during the `download` step, but this is intended to be run
    /// just before a crate is compiled so it may perform more expensive checks
    /// which may not be cacheable.
    fn verify(&self, _pkg: &PackageId) -> CargoResult<()> {
        Ok(())
    }

    /// Describes this source in a human readable fashion, used for display in
    /// resolver error messages currently.
    fn describe(&self) -> String;

    /// Returns whether a source is being replaced by another here
    fn is_replaced(&self) -> bool {
        false
    }
}

pub enum MaybePackage {
    Ready(Package),
    Download { url: String, descriptor: String },
}

impl<'a, T: Source + ?Sized + 'a> Source for Box<T> {
    /// Forwards to `Source::source_id`
    fn source_id(&self) -> &SourceId {
        (**self).source_id()
    }

    /// Forwards to `Source::replaced_source_id`
    fn replaced_source_id(&self) -> &SourceId {
        (**self).replaced_source_id()
    }

    /// Forwards to `Source::supports_checksums`
    fn supports_checksums(&self) -> bool {
        (**self).supports_checksums()
    }

    /// Forwards to `Source::requires_precise`
    fn requires_precise(&self) -> bool {
        (**self).requires_precise()
    }

    /// Forwards to `Source::query`
    fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
        (**self).query(dep, f)
    }

    /// Forwards to `Source::query`
    fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
        (**self).fuzzy_query(dep, f)
    }

    /// Forwards to `Source::update`
    fn update(&mut self) -> CargoResult<()> {
        (**self).update()
    }

    /// Forwards to `Source::download`
    fn download(&mut self, id: &PackageId) -> CargoResult<MaybePackage> {
        (**self).download(id)
    }

    fn finish_download(&mut self, id: &PackageId, data: Vec<u8>) -> CargoResult<Package> {
        (**self).finish_download(id, data)
    }

    /// Forwards to `Source::fingerprint`
    fn fingerprint(&self, pkg: &Package) -> CargoResult<String> {
        (**self).fingerprint(pkg)
    }

    /// Forwards to `Source::verify`
    fn verify(&self, pkg: &PackageId) -> CargoResult<()> {
        (**self).verify(pkg)
    }

    fn describe(&self) -> String {
        (**self).describe()
    }

    fn is_replaced(&self) -> bool {
        (**self).is_replaced()
    }
}

impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T {
    fn source_id(&self) -> &SourceId {
        (**self).source_id()
    }

    fn replaced_source_id(&self) -> &SourceId {
        (**self).replaced_source_id()
    }

    fn supports_checksums(&self) -> bool {
        (**self).supports_checksums()
    }

    fn requires_precise(&self) -> bool {
        (**self).requires_precise()
    }

    fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
        (**self).query(dep, f)
    }

    fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
        (**self).fuzzy_query(dep, f)
    }

    fn update(&mut self) -> CargoResult<()> {
        (**self).update()
    }

    fn download(&mut self, id: &PackageId) -> CargoResult<MaybePackage> {
        (**self).download(id)
    }

    fn finish_download(&mut self, id: &PackageId, data: Vec<u8>) -> CargoResult<Package> {
        (**self).finish_download(id, data)
    }

    fn fingerprint(&self, pkg: &Package) -> CargoResult<String> {
        (**self).fingerprint(pkg)
    }

    fn verify(&self, pkg: &PackageId) -> CargoResult<()> {
        (**self).verify(pkg)
    }

    fn describe(&self) -> String {
        (**self).describe()
    }

    fn is_replaced(&self) -> bool {
        (**self).is_replaced()
    }
}

/// A `HashMap` of `SourceId` -> `Box<Source>`
#[derive(Default)]
pub struct SourceMap<'src> {
    map: HashMap<SourceId, Box<Source + 'src>>,
}

// impl debug on source requires specialization, if even desirable at all
impl<'src> fmt::Debug for SourceMap<'src> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SourceMap ")?;
        f.debug_set().entries(self.map.keys()).finish()
    }
}

/// A `std::collection::hash_map::Values` for `SourceMap`
pub type Sources<'a, 'src> = Values<'a, SourceId, Box<Source + 'src>>;

/// A `std::collection::hash_map::IterMut` for `SourceMap`
pub struct SourcesMut<'a, 'src: 'a> {
    inner: IterMut<'a, SourceId, Box<Source + 'src>>,
}

impl<'src> SourceMap<'src> {
    /// Create an empty map
    pub fn new() -> SourceMap<'src> {
        SourceMap {
            map: HashMap::new(),
        }
    }

    /// Like `HashMap::contains_key`
    pub fn contains(&self, id: &SourceId) -> bool {
        self.map.contains_key(id)
    }

    /// Like `HashMap::get`
    pub fn get(&self, id: &SourceId) -> Option<&(Source + 'src)> {
        let source = self.map.get(id);

        source.map(|s| {
            let s: &(Source + 'src) = &**s;
            s
        })
    }

    /// Like `HashMap::get_mut`
    pub fn get_mut(&mut self, id: &SourceId) -> Option<&mut (Source + 'src)> {
        self.map.get_mut(id).map(|s| {
            let s: &mut (Source + 'src) = &mut **s;
            s
        })
    }

    /// Like `HashMap::get`, but first calculates the `SourceId` from a
    /// `PackageId`
    pub fn get_by_package_id(&self, pkg_id: &PackageId) -> Option<&(Source + 'src)> {
        self.get(pkg_id.source_id())
    }

    /// Like `HashMap::insert`, but derives the SourceId key from the Source
    pub fn insert(&mut self, source: Box<Source + 'src>) {
        let id = source.source_id().clone();
        self.map.insert(id, source);
    }

    /// Like `HashMap::is_empty`
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Like `HashMap::len`
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Like `HashMap::values`
    pub fn sources<'a>(&'a self) -> Sources<'a, 'src> {
        self.map.values()
    }

    /// Like `HashMap::iter_mut`
    pub fn sources_mut<'a>(&'a mut self) -> SourcesMut<'a, 'src> {
        SourcesMut {
            inner: self.map.iter_mut(),
        }
    }
}

impl<'a, 'src> Iterator for SourcesMut<'a, 'src> {
    type Item = (&'a SourceId, &'a mut (Source + 'src));
    fn next(&mut self) -> Option<(&'a SourceId, &'a mut (Source + 'src))> {
        self.inner.next().map(|(a, b)| (a, &mut **b))
    }
}
<commit_msg>use impl Iterator instead of custom types in `source`<commit_after>use std::collections::hash_map::HashMap;
use std::fmt;

use core::{Dependency, Package, PackageId, Summary};
use util::CargoResult;

mod source_id;

pub use self::source_id::{GitReference, SourceId};

/// A Source finds and downloads remote packages based on names and
/// versions.
pub trait Source {
    /// Returns the `SourceId` corresponding to this source
    fn source_id(&self) -> &SourceId;

    /// Returns the replaced `SourceId` corresponding to this source
    fn replaced_source_id(&self) -> &SourceId {
        self.source_id()
    }

    /// Returns whether or not this source will return summaries with
    /// checksums listed.
    fn supports_checksums(&self) -> bool;

    /// Returns whether or not this source will return summaries with
    /// the `precise` field in the source id listed.
    fn requires_precise(&self) -> bool;

    /// Attempt to find the packages that match a dependency request.
    fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()>;

    /// Attempt to find the packages that are close to a dependency request.
    /// Each source gets to define what `close` means for it.
    /// path/git sources may return all dependencies that are at that uri.
    /// where as an Index source may return dependencies that have the same canonicalization.
    fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()>;

    fn query_vec(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
        let mut ret = Vec::new();
        self.query(dep, &mut |s| ret.push(s))?;
        Ok(ret)
    }

    /// The update method performs any network operations required to
    /// get the entire list of all names, versions and dependencies of
    /// packages managed by the Source.
    fn update(&mut self) -> CargoResult<()>;

    /// The download method fetches the full package for each name and
    /// version specified.
    fn download(&mut self, package: &PackageId) -> CargoResult<MaybePackage>;

    fn finish_download(&mut self, package: &PackageId, contents: Vec<u8>) -> CargoResult<Package>;

    /// Generates a unique string which represents the fingerprint of the
    /// current state of the source.
    ///
    /// This fingerprint is used to determine the "fresheness" of the source
    /// later on. It must be guaranteed that the fingerprint of a source is
    /// constant if and only if the output product will remain constant.
    ///
    /// The `pkg` argument is the package which this fingerprint should only be
    /// interested in for when this source may contain multiple packages.
    fn fingerprint(&self, pkg: &Package) -> CargoResult<String>;

    /// If this source supports it, verifies the source of the package
    /// specified.
    ///
    /// Note that the source may also have performed other checksum-based
    /// verification during the `download` step, but this is intended to be run
    /// just before a crate is compiled so it may perform more expensive checks
    /// which may not be cacheable.
    fn verify(&self, _pkg: &PackageId) -> CargoResult<()> {
        Ok(())
    }

    /// Describes this source in a human readable fashion, used for display in
    /// resolver error messages currently.
    fn describe(&self) -> String;

    /// Returns whether a source is being replaced by another here
    fn is_replaced(&self) -> bool {
        false
    }
}

pub enum MaybePackage {
    Ready(Package),
    Download { url: String, descriptor: String },
}

impl<'a, T: Source + ?Sized + 'a> Source for Box<T> {
    /// Forwards to `Source::source_id`
    fn source_id(&self) -> &SourceId {
        (**self).source_id()
    }

    /// Forwards to `Source::replaced_source_id`
    fn replaced_source_id(&self) -> &SourceId {
        (**self).replaced_source_id()
    }

    /// Forwards to `Source::supports_checksums`
    fn supports_checksums(&self) -> bool {
        (**self).supports_checksums()
    }

    /// Forwards to `Source::requires_precise`
    fn requires_precise(&self) -> bool {
        (**self).requires_precise()
    }

    /// Forwards to `Source::query`
    fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
        (**self).query(dep, f)
    }

    /// Forwards to `Source::query`
    fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
        (**self).fuzzy_query(dep, f)
    }

    /// Forwards to `Source::update`
    fn update(&mut self) -> CargoResult<()> {
        (**self).update()
    }

    /// Forwards to `Source::download`
    fn download(&mut self, id: &PackageId) -> CargoResult<MaybePackage> {
        (**self).download(id)
    }

    fn finish_download(&mut self, id: &PackageId, data: Vec<u8>) -> CargoResult<Package> {
        (**self).finish_download(id, data)
    }

    /// Forwards to `Source::fingerprint`
    fn fingerprint(&self, pkg: &Package) -> CargoResult<String> {
        (**self).fingerprint(pkg)
    }

    /// Forwards to `Source::verify`
    fn verify(&self, pkg: &PackageId) -> CargoResult<()> {
        (**self).verify(pkg)
    }

    fn describe(&self) -> String {
        (**self).describe()
    }

    fn is_replaced(&self) -> bool {
        (**self).is_replaced()
    }
}

impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T {
    fn source_id(&self) -> &SourceId {
        (**self).source_id()
    }

    fn replaced_source_id(&self) -> &SourceId {
        (**self).replaced_source_id()
    }

    fn supports_checksums(&self) -> bool {
        (**self).supports_checksums()
    }

    fn requires_precise(&self) -> bool {
        (**self).requires_precise()
    }

    fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
        (**self).query(dep, f)
    }

    fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
        (**self).fuzzy_query(dep, f)
    }

    fn update(&mut self) -> CargoResult<()> {
        (**self).update()
    }

    fn download(&mut self, id: &PackageId) -> CargoResult<MaybePackage> {
        (**self).download(id)
    }

    fn finish_download(&mut self, id: &PackageId, data: Vec<u8>) -> CargoResult<Package> {
        (**self).finish_download(id, data)
    }

    fn fingerprint(&self, pkg: &Package) -> CargoResult<String> {
        (**self).fingerprint(pkg)
    }

    fn verify(&self, pkg: &PackageId) -> CargoResult<()> {
        (**self).verify(pkg)
    }

    fn describe(&self) -> String {
        (**self).describe()
    }

    fn is_replaced(&self) -> bool {
        (**self).is_replaced()
    }
}

/// A `HashMap` of `SourceId` -> `Box<Source>`
#[derive(Default)]
pub struct SourceMap<'src> {
    map: HashMap<SourceId, Box<Source + 'src>>,
}

// impl debug on source requires specialization, if even desirable at all
impl<'src> fmt::Debug for SourceMap<'src> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SourceMap ")?;
        f.debug_set().entries(self.map.keys()).finish()
    }
}

impl<'src> SourceMap<'src> {
    /// Create an empty map
    pub fn new() -> SourceMap<'src> {
        SourceMap {
            map: HashMap::new(),
        }
    }

    /// Like `HashMap::contains_key`
    pub fn contains(&self, id: &SourceId) -> bool {
        self.map.contains_key(id)
    }

    /// Like `HashMap::get`
    pub fn get(&self, id: &SourceId) -> Option<&(Source + 'src)> {
        let source = self.map.get(id);

        source.map(|s| {
            let s: &(Source + 'src) = &**s;
            s
        })
    }

    /// Like `HashMap::get_mut`
    pub fn get_mut(&mut self, id: &SourceId) -> Option<&mut (Source + 'src)> {
        self.map.get_mut(id).map(|s| {
            let s: &mut (Source + 'src) = &mut **s;
            s
        })
    }

    /// Like `HashMap::get`, but first calculates the `SourceId` from a
    /// `PackageId`
    pub fn get_by_package_id(&self, pkg_id: &PackageId) -> Option<&(Source + 'src)> {
        self.get(pkg_id.source_id())
    }

    /// Like `HashMap::insert`, but derives the SourceId key from the Source
    pub fn insert(&mut self, source: Box<Source + 'src>) {
        let id = source.source_id().clone();
        self.map.insert(id, source);
    }

    /// Like `HashMap::is_empty`
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Like `HashMap::len`
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Like `HashMap::values`
    pub fn sources<'a>(&'a self) -> impl Iterator<Item = &'a Box<Source + 'src>> {
        self.map.values()
    }

    /// Like `HashMap::iter_mut`
    pub fn sources_mut<'a>(
        &'a mut self,
    ) -> impl Iterator<Item = (&'a SourceId, &'a mut (Source + 'src))> {
        self.map.iter_mut().map(|(a, b)| (a, &mut **b))
    }
}
<|endoftext|>


<commit_before>mod printer;
mod name_matcher;
mod caseless_name_matcher;
mod logical_matchers;
mod type_matcher;
use std::error::Error;
use std::fs::DirEntry;
use std::cell::RefCell;
use std::io::Write;
use std::rc::Rc;

/// A basic interface that can be used to determine whether a directory entry
/// is what's being searched for. To a first order approximation, find consists
/// of building a chain of Matcher objets, and then walking a directory tree,
/// passing each entry to the chain of Matchers.
pub trait Matcher {
    /// Returns whether the given file matches the object's predicate.
    fn matches(&self, file_info: &DirEntry) -> bool;

    /// Returns whether the matcher has any side-effects. Iff no such matcher
    /// exists in the chain, then the filename will be printed to stdout. While
    /// this is a compile-time fact for most matchers, it's run-time for matchers
    /// that contain a collection of sub-Matchers.
    fn has_side_effects(&self) -> bool;
}

/// Builds a single AndMatcher containing the Matcher objects corresponding
/// to the passed in predicate arguments.
pub fn build_top_level_matcher(args: &[&str],
                               output: Rc<RefCell<Write>>)
                               -> Result<Box<Matcher>, Box<Error>> {
    let mut top_level_matcher = logical_matchers::OrMatcher::new();

    // can't use getopts for a variety or reasons:
    // order ot arguments is important
    // arguments can start with + as well as -
    // multiple-character flags don't start with a double dash
    let mut i = 0;
    let mut invert_next_matcher = false;
    while i < args.len() {
        let possible_submatcher = match args[i] {
            "-print" => Some(Box::new(printer::Printer::new(output.clone())) as Box<Matcher>),
            "-true" => Some(Box::new(logical_matchers::TrueMatcher {}) as Box<Matcher>),
            "-false" => Some(Box::new(logical_matchers::FalseMatcher {}) as Box<Matcher>),
            "-name" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("missing argument to {}", args[i])));
                }
                i += 1;
                Some(Box::new(try!(name_matcher::NameMatcher::new(args[i]
                    .as_ref()))) as Box<Matcher>)
            }
            "-iname" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("missing argument to {}", args[i])));
                }
                i += 1;
                Some(Box::new(try!(caseless_name_matcher::CaselessNameMatcher::new(args[i]))) as Box<Matcher>)
            }
            "-type" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("missing argument to {}", args[i])));
                }
                i += 1;
                Some(Box::new(try!(type_matcher::TypeMatcher::new(args[i]))) as Box<Matcher>)
            }
            "-not" | "!" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("expected an expression after {}", args[i])));
                }
                invert_next_matcher = true;
                None
            }
            "-or" | "-o" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("expected an expression after {}", args[i])));
                }
                try!(top_level_matcher.new_ored_criterion(args[i]));
                None
            }
            _ => return Err(From::from(format!("Unrecognized flag: '{}'", args[i]))),
        };
        if let Some(submatcher) = possible_submatcher {
            if invert_next_matcher {
                top_level_matcher.push(Box::new(logical_matchers::NotMatcher::new(submatcher)));
                invert_next_matcher = false;
            } else {
                top_level_matcher.push(submatcher);
            }
        }
        i += 1;
    }

    if !top_level_matcher.has_side_effects() {
        top_level_matcher.push(Box::new(printer::Printer::new(output)));
    }
    Ok(Box::new(top_level_matcher))
}

#[cfg(test)]
mod tests {
    use std::fs::DirEntry;
    use std::cell::RefCell;
    use std::vec::Vec;
    use std::io::Cursor;
    use std::rc::Rc;
    use std::io::Read;

    /// Helper function for tests to get a DirEntry object. directory should
    /// probably be a string starting with "test_data/" (cargo's tests run with
    /// a working directory set to the root findutils folder).
    pub fn get_dir_entry_for(directory: &str, filename: &str) -> DirEntry {
        let dir_entries = ::std::fs::read_dir(directory).unwrap();
        for wrapped_dir_entry in dir_entries {
            let dir_entry = wrapped_dir_entry.unwrap();
            if dir_entry.file_name().to_string_lossy() == filename {
                return dir_entry;
            }
        }
        panic!("Couldn't find {} in {}", directory, filename);
    }

    fn new_output() -> Rc<RefCell<Cursor<Vec<u8>>>> {
        Rc::new(RefCell::new(Cursor::new(Vec::<u8>::new())))
    }

    fn assert_output_equals(output: &RefCell<Cursor<Vec<u8>>>, expected: &str) {
        let mut cursor = output.borrow_mut();
        cursor.set_position(0);
        let mut contents = String::new();
        cursor.read_to_string(&mut contents).unwrap();
        assert_eq!(expected, contents);
    }

    #[test]
    fn build_top_level_matcher_name() {
        let abbbc_lower = get_dir_entry_for("./test_data/simple", "abbbc");
        let abbbc_upper = get_dir_entry_for("./test_data/simple", "ABBBC");
        let output = new_output();

        let matcher = super::build_top_level_matcher(&["-name", "a*c"], output.clone()).unwrap();

        assert!(matcher.matches(&abbbc_lower));
        assert!(!matcher.matches(&abbbc_upper));
        assert_output_equals(&output, "./test_data/simple/abbbc\n");
    }

    #[test]
    fn build_top_level_matcher_iname() {
        let abbbc_lower = get_dir_entry_for("./test_data/simple", "abbbc");
        let abbbc_upper = get_dir_entry_for("./test_data/simple", "ABBBC");
        let output = new_output();

        let matcher = super::build_top_level_matcher(&["-iname", "a*c"], output.clone()).unwrap();

        assert!(matcher.matches(&abbbc_lower));
        assert!(matcher.matches(&abbbc_upper));
        assert_output_equals(&output,
                             "./test_data/simple/abbbc\n./test_data/simple/ABBBC\n");
    }

    #[test]
    fn build_top_level_matcher_not() {
        for arg in &["-not", "!"] {
            let abbbc_lower = get_dir_entry_for("./test_data/simple", "abbbc");
            let output = new_output();

            let matcher = super::build_top_level_matcher(&[arg, "-name", "doesntexist"],
                                                         output.clone())
                .unwrap();

            assert!(matcher.matches(&abbbc_lower));
            assert_output_equals(&output, "./test_data/simple/abbbc\n");
        }
    }

    #[test]
    fn build_top_level_matcher_not_needs_expression() {
        for arg in &["-not", "!"] {
            let output = new_output();

            if let Err(e) = super::build_top_level_matcher(&[arg], output.clone()) {
                assert!(e.description().contains("expected an expression"));
            } else {
                panic!("parsing arugment lists that end in -not should fail");
            }
        }
    }

    #[test]
    fn build_top_level_matcher_missing_args() {
        for arg in &["-iname", "-name", "-type"] {
            let output = new_output();

            if let Err(e) = super::build_top_level_matcher(&[arg], output.clone()) {
                assert!(e.description().contains("missing argument to"));
                assert!(e.description().contains(arg));
            } else {
                panic!("parsing arugment lists that end in -not should fail");
            }
        }
    }

    #[test]
    fn build_top_level_matcher_or_without_expr1() {
        for arg in &["-or", "-o"] {
            let output = new_output();

            if let Err(e) = super::build_top_level_matcher(&[arg, "-true"], output.clone()) {
                assert!(e.description().contains("you have used a binary operator"));
            } else {
                panic!("parsing arugment list that begins with -or should fail");
            }
        }
    }

    #[test]
    fn build_top_level_matcher_or_without_expr2() {
        for arg in &["-or", "-o"] {
            let output = new_output();

            if let Err(e) = super::build_top_level_matcher(&["-true", arg], output.clone()) {
                assert!(e.description().contains("expected an expression"));
            } else {
                panic!("parsing arugment list that ends with -or should fail");
            }
        }
    }

}
<commit_msg>Added change missing form last commit<commit_after>mod printer;
mod name_matcher;
mod caseless_name_matcher;
mod logical_matchers;
mod type_matcher;
use std::error::Error;
use std::fs::DirEntry;
use std::cell::RefCell;
use std::io::Write;
use std::rc::Rc;

/// A basic interface that can be used to determine whether a directory entry
/// is what's being searched for. To a first order approximation, find consists
/// of building a chain of Matcher objets, and then walking a directory tree,
/// passing each entry to the chain of Matchers.
pub trait Matcher {
    /// Returns whether the given file matches the object's predicate.
    fn matches(&self, file_info: &DirEntry) -> bool;

    /// Returns whether the matcher has any side-effects. Iff no such matcher
    /// exists in the chain, then the filename will be printed to stdout. While
    /// this is a compile-time fact for most matchers, it's run-time for matchers
    /// that contain a collection of sub-Matchers.
    fn has_side_effects(&self) -> bool;
}

/// Builds a single AndMatcher containing the Matcher objects corresponding
/// to the passed in predicate arguments.
pub fn build_top_level_matcher(args: &[&str],
                               output: Rc<RefCell<Write>>)
                               -> Result<Box<Matcher>, Box<Error>> {
    let mut top_level_matcher = logical_matchers::OrMatcher::new();

    // can't use getopts for a variety or reasons:
    // order ot arguments is important
    // arguments can start with + as well as -
    // multiple-character flags don't start with a double dash
    let mut i = 0;
    let mut invert_next_matcher = false;
    while i < args.len() {
        let possible_submatcher = match args[i] {
            "-print" => Some(Box::new(printer::Printer::new(output.clone())) as Box<Matcher>),
            "-true" => Some(Box::new(logical_matchers::TrueMatcher {}) as Box<Matcher>),
            "-false" => Some(Box::new(logical_matchers::FalseMatcher {}) as Box<Matcher>),
            "-name" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("missing argument to {}", args[i])));
                }
                i += 1;
                Some(Box::new(try!(name_matcher::NameMatcher::new(args[i]
                    .as_ref()))) as Box<Matcher>)
            }
            "-iname" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("missing argument to {}", args[i])));
                }
                i += 1;
                Some(Box::new(try!(caseless_name_matcher::CaselessNameMatcher::new(args[i]))) as Box<Matcher>)
            }
            "-type" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("missing argument to {}", args[i])));
                }
                i += 1;
                Some(Box::new(try!(type_matcher::TypeMatcher::new(args[i]))) as Box<Matcher>)
            }
            "-not" | "!" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("expected an expression after {}", args[i])));
                }
                invert_next_matcher = true;
                None
            }
            "-or" | "-o" => {
                if i >= args.len() - 1 {
                    return Err(From::from(format!("expected an expression after {}", args[i])));
                }
                try!(top_level_matcher.new_ored_criterion(args[i]));
                None
            }
            _ => return Err(From::from(format!("Unrecognized flag: '{}'", args[i]))),
        };
        if let Some(submatcher) = possible_submatcher {
            if invert_next_matcher {
                top_level_matcher.push(Box::new(logical_matchers::NotMatcher::new(submatcher)));
                invert_next_matcher = false;
            } else {
                top_level_matcher.push(submatcher);
            }
        }
        i += 1;
    }

    if !top_level_matcher.has_side_effects() {
        let mut new_and_matcher = logical_matchers::AndMatcher::new();
        new_and_matcher.push(Box::new(top_level_matcher));
        new_and_matcher.push(Box::new(printer::Printer::new(output)));
        return Ok(Box::new(new_and_matcher));
    }
    Ok(Box::new(top_level_matcher))
}

#[cfg(test)]
mod tests {
    use std::fs::DirEntry;
    use std::cell::RefCell;
    use std::vec::Vec;
    use std::io::Cursor;
    use std::rc::Rc;
    use std::io::Read;

    /// Helper function for tests to get a DirEntry object. directory should
    /// probably be a string starting with "test_data/" (cargo's tests run with
    /// a working directory set to the root findutils folder).
    pub fn get_dir_entry_for(directory: &str, filename: &str) -> DirEntry {
        let dir_entries = ::std::fs::read_dir(directory).unwrap();
        for wrapped_dir_entry in dir_entries {
            let dir_entry = wrapped_dir_entry.unwrap();
            if dir_entry.file_name().to_string_lossy() == filename {
                return dir_entry;
            }
        }
        panic!("Couldn't find {} in {}", directory, filename);
    }

    fn new_output() -> Rc<RefCell<Cursor<Vec<u8>>>> {
        Rc::new(RefCell::new(Cursor::new(Vec::<u8>::new())))
    }

    fn get_output_as_string(output: &RefCell<Cursor<Vec<u8>>>) -> String {
        let mut cursor = output.borrow_mut();
        cursor.set_position(0);
        let mut contents = String::new();
        cursor.read_to_string(&mut contents).unwrap();
        contents
    }

    #[test]
    fn build_top_level_matcher_name() {
        let abbbc_lower = get_dir_entry_for("./test_data/simple", "abbbc");
        let abbbc_upper = get_dir_entry_for("./test_data/simple", "ABBBC");
        let output = new_output();

        let matcher = super::build_top_level_matcher(&["-name", "a*c"], output.clone()).unwrap();

        assert!(matcher.matches(&abbbc_lower));
        assert!(!matcher.matches(&abbbc_upper));
        assert_eq!(get_output_as_string(&output), "./test_data/simple/abbbc\n");
    }

    #[test]
    fn build_top_level_matcher_iname() {
        let abbbc_lower = get_dir_entry_for("./test_data/simple", "abbbc");
        let abbbc_upper = get_dir_entry_for("./test_data/simple", "ABBBC");
        let output = new_output();

        let matcher = super::build_top_level_matcher(&["-iname", "a*c"], output.clone()).unwrap();

        assert!(matcher.matches(&abbbc_lower));
        assert!(matcher.matches(&abbbc_upper));
        assert_eq!(get_output_as_string(&output),
                   "./test_data/simple/abbbc\n./test_data/simple/ABBBC\n");
    }

    #[test]
    fn build_top_level_matcher_not() {
        for arg in &["-not", "!"] {
            let abbbc_lower = get_dir_entry_for("./test_data/simple", "abbbc");
            let output = new_output();

            let matcher = super::build_top_level_matcher(&[arg, "-name", "doesntexist"],
                                                         output.clone())
                .unwrap();

            assert!(matcher.matches(&abbbc_lower));
            assert_eq!(get_output_as_string(&output), "./test_data/simple/abbbc\n");
        }
    }

    #[test]
    fn build_top_level_matcher_not_needs_expression() {
        for arg in &["-not", "!"] {
            let output = new_output();

            if let Err(e) = super::build_top_level_matcher(&[arg], output.clone()) {
                assert!(e.description().contains("expected an expression"));
            } else {
                panic!("parsing arugment lists that end in -not should fail");
            }
        }
    }

    #[test]
    fn build_top_level_matcher_missing_args() {
        for arg in &["-iname", "-name", "-type"] {
            let output = new_output();

            if let Err(e) = super::build_top_level_matcher(&[arg], output.clone()) {
                assert!(e.description().contains("missing argument to"));
                assert!(e.description().contains(arg));
            } else {
                panic!("parsing arugment lists that end in -not should fail");
            }
        }
    }

    #[test]
    fn build_top_level_matcher_or_without_expr1() {
        for arg in &["-or", "-o"] {
            let output = new_output();

            if let Err(e) = super::build_top_level_matcher(&[arg, "-true"], output.clone()) {
                assert!(e.description().contains("you have used a binary operator"));
            } else {
                panic!("parsing arugment list that begins with -or should fail");
            }
        }
    }

    #[test]
    fn build_top_level_matcher_or_without_expr2() {
        for arg in &["-or", "-o"] {
            let output = new_output();

            if let Err(e) = super::build_top_level_matcher(&["-true", arg], output.clone()) {
                assert!(e.description().contains("expected an expression"));
            } else {
                panic!("parsing arugment list that ends with -or should fail");
            }
        }
    }

    #[test]
    fn build_top_level_matcher_or_works() {
        let abbbc = get_dir_entry_for("./test_data/simple", "abbbc");
        for args in &[["-true", "-o", "-false"],
                      ["-false", "-o", "-true"],
                      ["-true", "-o", "-true"]] {
            let output = new_output();

            let matcher = super::build_top_level_matcher(args, output.clone()).unwrap();

            assert!(matcher.matches(&abbbc));
            assert_eq!(get_output_as_string(&output), "./test_data/simple/abbbc\n");
        }

        let output = new_output();

        let matcher = super::build_top_level_matcher(&["-false", "-o", "-false"], output.clone())
            .unwrap();

        assert!(!matcher.matches(&abbbc));
        assert_eq!(get_output_as_string(&output), "");
    }

    #[test]
    fn build_top_level_matcher_and_works() {
        let abbbc = get_dir_entry_for("./test_data/simple", "abbbc");
        for args in &[["-true", "-false"], ["-false", "-true"], ["-false", "-false"]] {
            let output = new_output();

            let matcher = super::build_top_level_matcher(args, output.clone()).unwrap();

            assert!(!matcher.matches(&abbbc));
            assert_eq!(get_output_as_string(&output), "");
        }

        let output = new_output();

        let matcher = super::build_top_level_matcher(&["-true", "-true"], output.clone()).unwrap();

        assert!(matcher.matches(&abbbc));
        assert_eq!(get_output_as_string(&output), "./test_data/simple/abbbc\n");
    }
}
<|endoftext|>


<commit_before>/// Lang item required to make the normal `main` work in applications
// This is how the `start` lang item works:
// When `rustc` compiles a binary crate, it creates a `main` function that looks
// like this:
//
// ```
// #[export_name = "main"]
// pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize {
//     start(main)
// }
// ```
//
// Where `start` is this function and `main` is the binary crate's `main`
// function.
//
// The final piece is that the entry point of our program, _start, has to call
// `rustc_main`. That's covered by the `_start` function in the root of this
// crate.
#[lang = "start"]
extern "C" fn start(
    main: fn(),
    _argc: isize,
    _argv: *const *const u8,
) -> isize {
    main();

    0
}

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[lang = "panic_fmt"]
unsafe extern "C" fn rust_begin_unwind() {
    loop {}
}
<commit_msg>Flash LEDs when panicking<commit_after>/// Lang item required to make the normal `main` work in applications
// This is how the `start` lang item works:
// When `rustc` compiles a binary crate, it creates a `main` function that looks
// like this:
//
// ```
// #[export_name = "main"]
// pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize {
//     start(main)
// }
// ```
//
// Where `start` is this function and `main` is the binary crate's `main`
// function.
//
// The final piece is that the entry point of our program, _start, has to call
// `rustc_main`. That's covered by the `_start` function in the root of this
// crate.
use led;
use timer;
#[lang = "start"]
extern "C" fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize {
    main();

    0
}

#[lang = "eh_personality"]
extern "C" fn eh_personality() {
    circle_leds(); // TODO: Make NRF52dK specific
}

#[lang = "panic_fmt"]
unsafe extern "C" fn rust_begin_unwind() {
    flash_all_leds(); // TODO: Make NRF52DK specific
}

fn circle_leds() {
    loop {
        led::on(0);
        timer::delay_ms(100);
        led::off(0);
        led::on(1);
        timer::delay_ms(100);
        led::off(1);
        led::on(3);
        timer::delay_ms(100);
        led::off(3);
        led::on(2);
        timer::delay_ms(100);
        led::off(2);
    }
}

fn flash_all_leds() {
    loop {
        led::on(0);
        led::on(1);
        led::on(2);
        led::on(3);
        timer::delay_ms(100);
        led::off(0);
        led::off(1);
        led::off(2);
        led::off(3);
        timer::delay_ms(100);
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(dead_code)]

use nom::{HexDisplay,IResult};
use nom::IResult::*;
use nom::Err::*;

use nom::{digit,is_alphanumeric};

use std::str;

// Primitives
fn is_token_char(i: u8) -> bool {
  is_alphanumeric(i) ||
  b"!#$%&'*+-.^_`|~".contains(&i)
}
named!(pub token, take_while!(is_token_char));

fn is_ws(i: u8) -> bool {
  i == ' ' as u8 && i == '\t' as u8
}
named!(pub repeated_ws, take_while!(is_ws));
named!(pub obsolete_ws, chain!(repeated_ws?, || { &b" "[..] }));

named!(pub sp<char>, char!(' '));
named!(pub crlf, tag!("\r\n"));

fn is_vchar(i: u8) -> bool {
  i > 32 && i <= 126
}
fn is_vchar_or_ws(i: u8) -> bool {
  is_vchar(i) || is_ws(i)
}

named!(pub vchar_1, take_while!(is_vchar));
named!(pub vchar_ws_1, take_while!(is_vchar_or_ws));

#[derive(PartialEq,Debug)]
pub struct RequestLine<'a> {
    pub method: &'a [u8],
    pub uri: &'a [u8],
    pub version: [&'a [u8];2]
}

#[derive(PartialEq,Debug,Clone)]
pub struct RRequestLine {
    pub method: String,
    pub uri: String,
    pub version: String
}

impl RRequestLine {
  pub fn from_request_line(r: RequestLine) -> Option<RRequestLine> {
    if let Ok(method) = str::from_utf8(r.method) {
      if let Ok(uri) = str::from_utf8(r.uri) {
        if let Ok(version1) = str::from_utf8(r.version[0]) {
          if let Ok(version2) = str::from_utf8(r.version[1]) {
            Some(RRequestLine {
              method:  String::from(method),
              uri:     String::from(uri),
              version: String::from(version1) + version2
            })
          } else {
            None
          }
        } else {
          None
        }
      } else {
        None
      }
    } else {
      None
    }
  }
}

named!(pub http_version<[&[u8];2]>,
       chain!(
        tag!("HTTP/") ~
        major: digit ~
        tag!(".") ~
        minor: digit, || {
            [minor, major] // ToDo do we need it?
        }
       )
);

named!(pub request_line<RequestLine>,
       chain!(
        method: token ~
        sp ~
        uri: vchar_1 ~ // ToDo proper URI parsing?
        sp ~
        version: http_version ~
        crlf, || {
            RequestLine {
              method: method,
              uri: uri,
              version: version
            }
        }
       )
);

#[derive(PartialEq,Debug)]
pub struct RequestHeader<'a> {
    pub name: &'a [u8],
    pub value: &'a [u8]
}

named!(pub message_header<RequestHeader>,
       chain!(
         name: token ~
         tag!(":") ~
         sp ~ // ToDo make it optional
         value: vchar_1 ~ // ToDo handle folding?
         crlf, || {
           RequestHeader {
            name: name,
            value: value
           }
         }
       )
);

named!(pub headers< Vec<RequestHeader> >, many0!(message_header));

#[derive(PartialEq,Debug)]
pub struct RequestHead<'a> {
    pub request_line: RequestLine<'a>,
    pub headers: Vec<RequestHeader<'a>>
}

named!(pub request_head<RequestHead>,
       chain!(
        rl: request_line ~
        hs: many0!(message_header) ~
        crlf, || {
          RequestHead {
            request_line: rl,
            headers: hs
          }
        }
       )
);

pub type Host = String;

#[derive(Debug,Clone)]
pub enum ErrorState {
  InvalidHttp,
  MissingHost
}

#[derive(Debug,Clone)]
pub enum LengthInformation {
  Length(usize),
  Chunked,
  Compressed
}

#[derive(Debug,Clone)]
pub enum HttpState {
  Initial,
  Error(ErrorState),
  HasRequestLine(usize, RRequestLine),
  HasHost(usize, RRequestLine, Host),
  HasLength(usize, RRequestLine, LengthInformation),
  HasHostAndLength(usize, RRequestLine, Host, LengthInformation),
  HeadersParsed(RRequestLine, Host, LengthInformation),
  Proxying(RRequestLine, Host)
  //Proxying(RRequestLine, Host, LengthInformation, BackendToken)
}

impl HttpState {
  pub fn get_host(&self) -> Option<String> {
    match *self {
      HttpState::HasHost(_,_, ref host) |
      HttpState::Proxying(_, ref host)    => Some(host.clone()),
      _                                   => None
    }
  }

  pub fn get_uri(&self) -> Option<String> {
    match *self {
      HttpState::HasRequestLine(_, ref rl) |
      HttpState::HasHost(_, ref rl,_)      |
      HttpState::Proxying(ref rl, _)         => Some(rl.uri.clone()),
      _                                      => None
    }
  }

  pub fn get_request_line(&self) -> Option<RRequestLine> {
    match *self {
      HttpState::HasRequestLine(_, ref rl) |
      HttpState::HasHost(_, ref rl,_)      |
      HttpState::Proxying(ref rl, _)         => Some(rl.clone()),
      _                                      => None
    }
  }
}

pub fn default_response<O>(state: &HttpState, res: IResult<&[u8], O>) -> HttpState {
  match res {
    IResult::Error(_)      => HttpState::Error(ErrorState::InvalidHttp),
    IResult::Incomplete(_) => state.clone(),
    _                      => unreachable!()
  }
}

pub fn parse_headers(state: &HttpState, buf: &[u8]) -> HttpState {
  match *state {
    HttpState::Initial => {
      //println!("buf: {}", buf.to_hex(8));
      match request_line(buf) {
        IResult::Done(i, r)    => {
          if let Some(rl) = RRequestLine::from_request_line(r) {
            let s = HttpState::HasRequestLine(buf.offset(i), rl);
            //println!("now in state: {:?}", s);
            parse_headers(&s, buf)
          } else {
            HttpState::Error(ErrorState::InvalidHttp)
          }
        },
        res => default_response(state, res)
      }
    },
    HttpState::HasRequestLine(pos, ref rl) => {
      //println!("parsing headers from:\n{}", (&buf[pos..]).to_hex(8));
      match headers(&buf[pos..]) {
        IResult::Done(i, v)    => {
          //println!("got headers: {:?}", v);
          let mut length_info:Option<LengthInformation> = None;
          for header in &v {
            match str::from_utf8(header.name) {
              Ok("Host") => {
                if let Ok(host) = str::from_utf8(header.value) {
                  if let Some(length) = length_info {
                    return HttpState::HasHostAndLength(buf.offset(i), rl.clone(), String::from(host), length);
                  } else {
                    return HttpState::HasHost(buf.offset(i), rl.clone(), String::from(host));
                  }
                } else {
                  return HttpState::Error(ErrorState::InvalidHttp);
                }
              },
              Ok("Content-Length") => {
                if let Ok(l) = str::from_utf8(header.value) {
                  match l.parse() {
                    Ok(length) => length_info = Some(LengthInformation::Length(length)),
                    Err(_)     => return HttpState::Error(ErrorState::InvalidHttp)
                  }
                } else {
                  return HttpState::Error(ErrorState::InvalidHttp);
                }
              }
              _ => {}
            }
          }

          if let Some(length) = length_info {
            HttpState::HasLength(buf.offset(i), rl.clone(), length)
          } else {
            HttpState::HasRequestLine(buf.offset(i), rl.clone())
          }
        },
        res => default_response(state, res)
      }
    },
    //HasHost(usize,RRequestLine, Host),
    _ => {
      println!("unimplemented state: {:?}", state);
      HttpState::Error(ErrorState::InvalidHttp)
    }
  }
}

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

  #[test]
  fn request_line_test() {
      let input = b"GET /index.html HTTP/1.1\r\n";
      let result = request_line(input);
      let expected = RequestLine {
        method: b"GET",
        uri: b"/index.html",
        version: [b"1", b"1"]
      };

      assert_eq!(result, Done(&[][..], expected));
  }

  #[test]
  fn header_test() {
      let input = b"Accept: */*\r\n";
      let result = message_header(input);
      let expected = RequestHeader {
        name: b"Accept",
        value: b"*/*"
      };

      assert_eq!(result, Done(&b""[..], expected))
  }

  #[test]
  fn request_head_test() {
      let input =
          b"GET /index.html HTTP/1.1\r\n\
            Host: localhost:8888\r\n\
            User-Agent: curl/7.43.0\r\n\
            Accept: */*\r\n\
            \r\n";
      let result = request_head(input);
      let expected = RequestHead {
        request_line: RequestLine {
        method: b"GET",
        uri: b"/index.html",
        version: [b"1", b"1"]
      },
        headers: vec!(
          RequestHeader {
            name: b"Host",
            value: b"localhost:8888"
          },
          RequestHeader {
            name: b"User-Agent",
            value: b"curl/7.43.0"
          },
          RequestHeader {
            name: b"Accept",
            value: b"*/*"
          }
        )
      };

      assert_eq!(result, Done(&b""[..], expected))
  }

  #[test]
  fn content_length_test() {
      let input =
          b"GET /index.html HTTP/1.1\r\n\
            Host: localhost:8888\r\n\
            User-Agent: curl/7.43.0\r\n\
            Accept: */*\r\n\
            Content-Length: 200\r\n\
            \r\n";
      let result = request_head(input);
      let expected = RequestHead {
        request_line: RequestLine {
        method: b"GET",
        uri: b"/index.html",
        version: [b"1", b"1"]
      },
        headers: vec!(
          RequestHeader {
            name: b"Host",
            value: b"localhost:8888"
          },
          RequestHeader {
            name: b"User-Agent",
            value: b"curl/7.43.0"
          },
          RequestHeader {
            name: b"Accept",
            value: b"*/*"
          },
          RequestHeader {
            name: b"Content-Length",
            value: b"200"
          }
        )
      };

      assert_eq!(result, Done(&b""[..], expected))
  }
}
<commit_msg>utility functions for header parsing<commit_after>#![allow(unused_imports)]
#![allow(dead_code)]

use nom::{HexDisplay,IResult};
use nom::IResult::*;
use nom::Err::*;

use nom::{digit,is_alphanumeric};

use std::str;

// Primitives
fn is_token_char(i: u8) -> bool {
  is_alphanumeric(i) ||
  b"!#$%&'*+-.^_`|~".contains(&i)
}
named!(pub token, take_while!(is_token_char));

fn is_ws(i: u8) -> bool {
  i == ' ' as u8 && i == '\t' as u8
}
named!(pub repeated_ws, take_while!(is_ws));
named!(pub obsolete_ws, chain!(repeated_ws?, || { &b" "[..] }));

named!(pub sp<char>, char!(' '));
named!(pub crlf, tag!("\r\n"));

fn is_vchar(i: u8) -> bool {
  i > 32 && i <= 126
}
fn is_vchar_or_ws(i: u8) -> bool {
  is_vchar(i) || is_ws(i)
}

named!(pub vchar_1, take_while!(is_vchar));
named!(pub vchar_ws_1, take_while!(is_vchar_or_ws));

#[derive(PartialEq,Debug)]
pub struct RequestLine<'a> {
    pub method: &'a [u8],
    pub uri: &'a [u8],
    pub version: [&'a [u8];2]
}

#[derive(PartialEq,Debug,Clone)]
pub struct RRequestLine {
    pub method: String,
    pub uri: String,
    pub version: String
}

impl RRequestLine {
  pub fn from_request_line(r: RequestLine) -> Option<RRequestLine> {
    if let Ok(method) = str::from_utf8(r.method) {
      if let Ok(uri) = str::from_utf8(r.uri) {
        if let Ok(version1) = str::from_utf8(r.version[0]) {
          if let Ok(version2) = str::from_utf8(r.version[1]) {
            Some(RRequestLine {
              method:  String::from(method),
              uri:     String::from(uri),
              version: String::from(version1) + version2
            })
          } else {
            None
          }
        } else {
          None
        }
      } else {
        None
      }
    } else {
      None
    }
  }
}

named!(pub http_version<[&[u8];2]>,
       chain!(
        tag!("HTTP/") ~
        major: digit ~
        tag!(".") ~
        minor: digit, || {
            [minor, major] // ToDo do we need it?
        }
       )
);

named!(pub request_line<RequestLine>,
       chain!(
        method: token ~
        sp ~
        uri: vchar_1 ~ // ToDo proper URI parsing?
        sp ~
        version: http_version ~
        crlf, || {
            RequestLine {
              method: method,
              uri: uri,
              version: version
            }
        }
       )
);

#[derive(PartialEq,Debug)]
pub struct RequestHeader<'a> {
    pub name: &'a [u8],
    pub value: &'a [u8]
}

named!(pub message_header<RequestHeader>,
       chain!(
         name: token ~
         tag!(":") ~
         sp ~ // ToDo make it optional
         value: vchar_1 ~ // ToDo handle folding?
         crlf, || {
           RequestHeader {
            name: name,
            value: value
           }
         }
       )
);

named!(pub headers< Vec<RequestHeader> >, many0!(message_header));

#[derive(PartialEq,Debug)]
pub struct RequestHead<'a> {
    pub request_line: RequestLine<'a>,
    pub headers: Vec<RequestHeader<'a>>
}

named!(pub request_head<RequestHead>,
       chain!(
        rl: request_line ~
        hs: many0!(message_header) ~
        crlf, || {
          RequestHead {
            request_line: rl,
            headers: hs
          }
        }
       )
);

#[derive(PartialEq,Debug)]
pub enum TransferEncoding {
  Chunked,
  Compress,
  Deflate,
  Gzip,
  Identity,
  Unknown
}

#[derive(PartialEq,Debug)]
pub enum Field<T> {
  Value(T),
  None,
  Error
}
impl<'a> RequestHeader<'a> {
  pub fn host(&self) -> Field<String> {
    if self.name == b"Host" {
      if let Some(s) = str::from_utf8(self.value).map(|s| String::from(s)).ok() {
        Field::Value(s)
      } else {
        Field::Error
      }
    } else {
      Field::None
    }
  }

  pub fn content_length(&self) -> Field<usize> {
    if self.name == b"Content-Length" {
      if let Ok(l) = str::from_utf8(self.value) {
        if let Some(length) = l.parse().ok() {
          return Field::Value(length)
        }
      }
      Field::Error
    } else {
      Field::None
    }
  }

  pub fn transfer_encoding(&self) -> Field<TransferEncoding> {
    if self.name == b"Transfer-Encoding" {
      match self.value {
        b"chunked"  => Field::Value(TransferEncoding::Chunked),
        b"compress" => Field::Value(TransferEncoding::Compress),
        b"deflate"  => Field::Value(TransferEncoding::Deflate),
        b"gzip"     => Field::Value(TransferEncoding::Gzip),
        b"identity" => Field::Value(TransferEncoding::Identity),
        _           => Field::Value(TransferEncoding::Unknown)
      }
    } else {
      Field::None
    }
  }
}

pub type Host = String;

#[derive(Debug,Clone)]
pub enum ErrorState {
  InvalidHttp,
  MissingHost
}

#[derive(Debug,Clone)]
pub enum LengthInformation {
  Length(usize),
  Chunked,
  Compressed
}

#[derive(Debug,Clone)]
pub enum HttpState {
  Initial,
  Error(ErrorState),
  HasRequestLine(usize, RRequestLine),
  HasHost(usize, RRequestLine, Host),
  HasLength(usize, RRequestLine, LengthInformation),
  HasHostAndLength(usize, RRequestLine, Host, LengthInformation),
  HeadersParsed(RRequestLine, Host, LengthInformation),
  Proxying(RRequestLine, Host)
  //Proxying(RRequestLine, Host, LengthInformation, BackendToken)
}

impl HttpState {
  pub fn get_host(&self) -> Option<String> {
    match *self {
      HttpState::HasHost(_,_, ref host) |
      HttpState::Proxying(_, ref host)    => Some(host.clone()),
      _                                   => None
    }
  }

  pub fn get_uri(&self) -> Option<String> {
    match *self {
      HttpState::HasRequestLine(_, ref rl) |
      HttpState::HasHost(_, ref rl,_)      |
      HttpState::Proxying(ref rl, _)         => Some(rl.uri.clone()),
      _                                      => None
    }
  }

  pub fn get_request_line(&self) -> Option<RRequestLine> {
    match *self {
      HttpState::HasRequestLine(_, ref rl) |
      HttpState::HasHost(_, ref rl,_)      |
      HttpState::Proxying(ref rl, _)         => Some(rl.clone()),
      _                                      => None
    }
  }
}

pub fn default_response<O>(state: &HttpState, res: IResult<&[u8], O>) -> HttpState {
  match res {
    IResult::Error(_)      => HttpState::Error(ErrorState::InvalidHttp),
    IResult::Incomplete(_) => state.clone(),
    _                      => unreachable!()
  }
}

pub fn parse_headers(state: &HttpState, buf: &[u8]) -> HttpState {
  match *state {
    HttpState::Initial => {
      //println!("buf: {}", buf.to_hex(8));
      match request_line(buf) {
        IResult::Done(i, r)    => {
          if let Some(rl) = RRequestLine::from_request_line(r) {
            let s = HttpState::HasRequestLine(buf.offset(i), rl);
            //println!("now in state: {:?}", s);
            parse_headers(&s, buf)
          } else {
            HttpState::Error(ErrorState::InvalidHttp)
          }
        },
        res => default_response(state, res)
      }
    },
    HttpState::HasRequestLine(pos, ref rl) => {
      //println!("parsing headers from:\n{}", (&buf[pos..]).to_hex(8));
      match headers(&buf[pos..]) {
        IResult::Done(i, v)    => {
          //println!("got headers: {:?}", v);
          let mut length_info:Option<LengthInformation> = None;
          for header in &v {
            match str::from_utf8(header.name) {
              Ok("Host") => {
                if let Ok(host) = str::from_utf8(header.value) {
                  if let Some(length) = length_info {
                    return HttpState::HasHostAndLength(buf.offset(i), rl.clone(), String::from(host), length);
                  } else {
                    return HttpState::HasHost(buf.offset(i), rl.clone(), String::from(host));
                  }
                } else {
                  return HttpState::Error(ErrorState::InvalidHttp);
                }
              },
              Ok("Content-Length") => {
                if let Ok(l) = str::from_utf8(header.value) {
                  match l.parse() {
                    Ok(length) => length_info = Some(LengthInformation::Length(length)),
                    Err(_)     => return HttpState::Error(ErrorState::InvalidHttp)
                  }
                } else {
                  return HttpState::Error(ErrorState::InvalidHttp);
                }
              }
              _ => {}
            }
          }

          if let Some(length) = length_info {
            HttpState::HasLength(buf.offset(i), rl.clone(), length)
          } else {
            HttpState::HasRequestLine(buf.offset(i), rl.clone())
          }
        },
        res => default_response(state, res)
      }
    },
    //HasHost(usize,RRequestLine, Host),
    _ => {
      println!("unimplemented state: {:?}", state);
      HttpState::Error(ErrorState::InvalidHttp)
    }
  }
}

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

  #[test]
  fn request_line_test() {
      let input = b"GET /index.html HTTP/1.1\r\n";
      let result = request_line(input);
      let expected = RequestLine {
        method: b"GET",
        uri: b"/index.html",
        version: [b"1", b"1"]
      };

      assert_eq!(result, Done(&[][..], expected));
  }

  #[test]
  fn header_test() {
      let input = b"Accept: */*\r\n";
      let result = message_header(input);
      let expected = RequestHeader {
        name: b"Accept",
        value: b"*/*"
      };

      assert_eq!(result, Done(&b""[..], expected))
  }

  #[test]
  fn request_head_test() {
      let input =
          b"GET /index.html HTTP/1.1\r\n\
            Host: localhost:8888\r\n\
            User-Agent: curl/7.43.0\r\n\
            Accept: */*\r\n\
            \r\n";
      let result = request_head(input);
      let expected = RequestHead {
        request_line: RequestLine {
        method: b"GET",
        uri: b"/index.html",
        version: [b"1", b"1"]
      },
        headers: vec!(
          RequestHeader {
            name: b"Host",
            value: b"localhost:8888"
          },
          RequestHeader {
            name: b"User-Agent",
            value: b"curl/7.43.0"
          },
          RequestHeader {
            name: b"Accept",
            value: b"*/*"
          }
        )
      };

      assert_eq!(result, Done(&b""[..], expected))
  }

  #[test]
  fn content_length_test() {
      let input =
          b"GET /index.html HTTP/1.1\r\n\
            Host: localhost:8888\r\n\
            User-Agent: curl/7.43.0\r\n\
            Accept: */*\r\n\
            Content-Length: 200\r\n\
            \r\n";
      let result = request_head(input);
      let expected = RequestHead {
        request_line: RequestLine {
        method: b"GET",
        uri: b"/index.html",
        version: [b"1", b"1"]
      },
        headers: vec!(
          RequestHeader {
            name: b"Host",
            value: b"localhost:8888"
          },
          RequestHeader {
            name: b"User-Agent",
            value: b"curl/7.43.0"
          },
          RequestHeader {
            name: b"Accept",
            value: b"*/*"
          },
          RequestHeader {
            name: b"Content-Length",
            value: b"200"
          }
        )
      };

      assert_eq!(result, Done(&b""[..], expected))
  }
}
<|endoftext|>


<commit_before>macro_rules! deref {
    ($name:ident::$field:tt => $target:ty) => (itemize! {
        impl ::std::ops::Deref for $name {
            type Target = $target;

            #[inline]
            fn deref(&self) -> &Self::Target {
                &self.$field
            }
        }
    });
    (mut $name:ident::$field:tt => $target:ty) => (itemize! {
        impl ::std::ops::DerefMut for $name {
            #[inline]
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.$field
            }
        }
    });
}

macro_rules! itemize(($($blob:item)*) => ($($blob)*));

macro_rules! getters {
    () => ();
    ($name:ident: $kind:ty, $($tail:tt)*) => (
        #[inline(always)]
        pub fn $name(&self) -> $kind {
            self.$name
        }
        getters! { $($tail)* }
    );
    (ref $name:ident: $kind:ty, $($tail:tt)*) => (
        #[inline(always)]
        pub fn $name(&self) -> &$kind {
            &self.$name
        }
        getters! { $($tail)* }
    );
}

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! order {
    ($name:ident($field:tt) ascending) => (order! { $name($field) Less < Greater });
    ($name:ident($field:tt) descending) => (order! { $name($field) Greater < Less });
    ($name:ident($field:tt) $less:ident < $greater:ident) => (itemize! {
        impl ::std::cmp::Eq for $name {
        }

        impl ::std::cmp::Ord for $name {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                if self.$field < other.$field {
                    ::std::cmp::Ordering::$less
                } else if self.$field > other.$field {
                    ::std::cmp::Ordering::$greater
                } else {
                    ::std::cmp::Ordering::Equal
                }
            }
        }

        impl ::std::cmp::PartialEq for $name {
            #[inline]
            fn eq(&self, other: &Self) -> bool {
                self.$field == other.$field
            }
        }

        impl ::std::cmp::PartialOrd for $name {
            #[inline]
            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
                Some(self.cmp(other))
            }
        }
    });
}

macro_rules! path(
    ($config:ident, $destination:expr) => ({
        let path = some!($config.get::<String>("path"), "the path to {} is missing", $destination);
        let mut path = ::std::path::PathBuf::from(path);
        if path.is_relative() {
            if let Some(root) = $config.get::<String>("root") {
                path = ::std::path::Path::new(root).join(path);
            }
        }
        if ::std::fs::metadata(&path).is_err() {
            raise!("the file {:?} does not exist", &path);
        }
        path
    });
);

macro_rules! raise(
    ($message:expr) => (return Err(::Error::new($message)));
    ($($arg:tt)*) => (return Err(::Error::new(format!($($arg)*))));
);

macro_rules! rewrite(
    ($header:tt [$($member:tt)*] {}) => (
        rewrite!(output $header [$($member)*]);
    );
    ($header:tt [$($member:tt)*] { pub $name:ident: $kind:ty, $($t:tt)* }) => (
        rewrite!($header [$($member)* pub $name: $kind,] { $($t)* });
    );
    ($header:tt [$($member:tt)*] { $name:ident: $kind:ty, $($t:tt)* }) => (
        rewrite!($header [$($member)* $name: $kind,] { $($t)* });
    );
    (output [$($chunk:tt)*] [$($member:tt)*]) => (
        itemize!(
            $($chunk)* {
                $($member)*
            }
        );
    );
);

macro_rules! some(
    ($option:expr) => (match $option {
        Some(value) => value,
        _ => raise!("encountered a logic error"),
    });
    ($option:expr, $($arg:tt)+) => (match $option {
        Some(value) => value,
        _ => raise!($($arg)*),
    });
);
<commit_msg>Remove a dead macro<commit_after>macro_rules! deref {
    ($name:ident::$field:tt => $target:ty) => (itemize! {
        impl ::std::ops::Deref for $name {
            type Target = $target;

            #[inline]
            fn deref(&self) -> &Self::Target {
                &self.$field
            }
        }
    });
    (mut $name:ident::$field:tt => $target:ty) => (itemize! {
        impl ::std::ops::DerefMut for $name {
            #[inline]
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.$field
            }
        }
    });
}

macro_rules! itemize(($($blob:item)*) => ($($blob)*));

macro_rules! getters {
    () => ();
    ($name:ident: $kind:ty, $($tail:tt)*) => (
        #[inline(always)]
        pub fn $name(&self) -> $kind {
            self.$name
        }
        getters! { $($tail)* }
    );
    (ref $name:ident: $kind:ty, $($tail:tt)*) => (
        #[inline(always)]
        pub fn $name(&self) -> &$kind {
            &self.$name
        }
        getters! { $($tail)* }
    );
}

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! order {
    ($name:ident($field:tt) ascending) => (order! { $name($field) Less < Greater });
    ($name:ident($field:tt) descending) => (order! { $name($field) Greater < Less });
    ($name:ident($field:tt) $less:ident < $greater:ident) => (itemize! {
        impl ::std::cmp::Eq for $name {
        }

        impl ::std::cmp::Ord for $name {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                if self.$field < other.$field {
                    ::std::cmp::Ordering::$less
                } else if self.$field > other.$field {
                    ::std::cmp::Ordering::$greater
                } else {
                    ::std::cmp::Ordering::Equal
                }
            }
        }

        impl ::std::cmp::PartialEq for $name {
            #[inline]
            fn eq(&self, other: &Self) -> bool {
                self.$field == other.$field
            }
        }

        impl ::std::cmp::PartialOrd for $name {
            #[inline]
            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
                Some(self.cmp(other))
            }
        }
    });
}

macro_rules! path(
    ($config:ident, $destination:expr) => ({
        let path = some!($config.get::<String>("path"), "the path to {} is missing", $destination);
        let mut path = ::std::path::PathBuf::from(path);
        if path.is_relative() {
            if let Some(root) = $config.get::<String>("root") {
                path = ::std::path::Path::new(root).join(path);
            }
        }
        if ::std::fs::metadata(&path).is_err() {
            raise!("the file {:?} does not exist", &path);
        }
        path
    });
);

macro_rules! raise(
    ($message:expr) => (return Err(::Error::new($message)));
    ($($arg:tt)*) => (return Err(::Error::new(format!($($arg)*))));
);

macro_rules! some(
    ($option:expr) => (match $option {
        Some(value) => value,
        _ => raise!("encountered a logic error"),
    });
    ($option:expr, $($arg:tt)+) => (match $option {
        Some(value) => value,
        _ => raise!($($arg)*),
    });
);
<|endoftext|>