<commit_before>use std::hash;
use std::fmt::{mod, Show, Formatter};

use semver::Version;
use serialize::{Encoder,Encodable};

use core::{Dependency, PackageId, Summary};
use core::package_id::Metadata;
use core::dependency::SerializedDependency;
use util::{CargoResult, human};

/// Contains all the informations about a package, as loaded from a Cargo.toml.
#[deriving(PartialEq,Clone)]
pub struct Manifest {
    summary: Summary,
    targets: Vec<Target>,
    target_dir: Path,
    doc_dir: Path,
    build: Vec<String>,
    warnings: Vec<String>,
    exclude: Vec<String>,
    metadata: ManifestMetadata,
}

impl Show for Manifest {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Manifest({}, targets={}, target_dir={}, \
                   build={})",
               self.summary, self.targets, self.target_dir.display(),
               self.build)
    }
}

/// General metadata about a package which is just blindly uploaded to the
/// registry.
///
/// Note that many of these fields can contain invalid values such as the
/// homepage, repository, documentation, or license. These fields are not
/// validated by cargo itself, but rather it is up to the registry when uploaded
/// to validate these fields. Cargo will itself accept any valid TOML
/// specification for these values.
#[deriving(PartialEq, Clone)]
pub struct ManifestMetadata {
    pub authors: Vec<String>,
    pub keywords: Vec<String>,
    pub license: Option<String>,
    pub description: Option<String>,    // not markdown
    pub readme: Option<String>,         // file, not contents
    pub homepage: Option<String>,       // url
    pub repository: Option<String>,     // url
    pub documentation: Option<String>,  // url
}

#[deriving(PartialEq,Clone,Encodable)]
pub struct SerializedManifest {
    name: String,
    version: String,
    dependencies: Vec<SerializedDependency>,
    targets: Vec<Target>,
    target_dir: String,
    doc_dir: String,
    build: Option<Vec<String>>,
}

impl<E, S: Encoder<E>> Encodable<S, E> for Manifest {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        SerializedManifest {
            name: self.summary.get_name().to_string(),
            version: self.summary.get_version().to_string(),
            dependencies: self.summary.get_dependencies().iter().map(|d| {
                SerializedDependency::from_dependency(d)
            }).collect(),
            targets: self.targets.clone(),
            target_dir: self.target_dir.display().to_string(),
            doc_dir: self.doc_dir.display().to_string(),
            build: if self.build.len() == 0 { None } else { Some(self.build.clone()) },
        }.encode(s)
    }
}

#[deriving(Show, Clone, PartialEq, Hash, Encodable)]
pub enum LibKind {
    Lib,
    Rlib,
    Dylib,
    StaticLib
}

impl LibKind {
    pub fn from_str(string: &str) -> CargoResult<LibKind> {
        match string {
            "lib" => Ok(Lib),
            "rlib" => Ok(Rlib),
            "dylib" => Ok(Dylib),
            "staticlib" => Ok(StaticLib),
            _ => Err(human(format!("{} was not one of lib|rlib|dylib|staticlib",
                                   string)))
        }
    }

    pub fn from_strs<S: Str>(strings: Vec<S>) -> CargoResult<Vec<LibKind>> {
        strings.iter().map(|s| LibKind::from_str(s.as_slice())).collect()
    }

    /// Returns the argument suitable for `--crate-type` to pass to rustc.
    pub fn crate_type(&self) -> &'static str {
        match *self {
            Lib => "lib",
            Rlib => "rlib",
            Dylib => "dylib",
            StaticLib => "staticlib"
        }
    }
}

#[deriving(Show, Clone, Hash, PartialEq, Encodable)]
pub enum TargetKind {
    LibTarget(Vec<LibKind>),
    BinTarget,
    ExampleTarget,
}

#[deriving(Encodable, Decodable, Clone, PartialEq, Show)]
pub struct Profile {
    env: String, // compile, test, dev, bench, etc.
    opt_level: uint,
    codegen_units: Option<uint>,    // None = use rustc default
    debug: bool,
    rpath: bool,
    test: bool,
    doctest: bool,
    doc: bool,
    dest: Option<String>,
    plugin: bool,
    harness: bool, // whether to use the test harness (--test)
}

impl Profile {
    fn default() -> Profile {
        Profile {
            env: String::new(),
            opt_level: 0,
            codegen_units: None,
            debug: false,
            rpath: false,
            test: false,
            doc: false,
            dest: None,
            plugin: false,
            doctest: false,
            harness: true,
        }
    }

    pub fn default_dev() -> Profile {
        Profile {
            env: "compile".to_string(), // run in the default environment only
            opt_level: 0,
            debug: true,
            .. Profile::default()
        }
    }

    pub fn default_test() -> Profile {
        Profile {
            env: "test".to_string(),
            debug: true,
            test: true,
            dest: None,
            .. Profile::default()
        }
    }

    pub fn default_bench() -> Profile {
        Profile {
            env: "bench".to_string(),
            opt_level: 3,
            test: true,
            dest: Some("release".to_string()),
            .. Profile::default()
        }
    }

    pub fn default_release() -> Profile {
        Profile {
            env: "release".to_string(),
            opt_level: 3,
            dest: Some("release".to_string()),
            .. Profile::default()
        }
    }

    pub fn default_doc() -> Profile {
        Profile {
            env: "doc".to_string(),
            dest: None,
            doc: true,
            .. Profile::default()
        }
    }

    pub fn is_compile(&self) -> bool {
        self.env.as_slice() == "compile"
    }

    pub fn is_doc(&self) -> bool {
        self.doc
    }

    pub fn is_test(&self) -> bool {
        self.test
    }

    pub fn uses_test_harness(&self) -> bool {
        self.harness
    }

    pub fn is_doctest(&self) -> bool {
        self.doctest
    }

    pub fn is_plugin(&self) -> bool {
        self.plugin
    }

    pub fn get_opt_level(&self) -> uint {
        self.opt_level
    }

    pub fn get_codegen_units(&self) -> Option<uint> {
        self.codegen_units
    }

    pub fn get_debug(&self) -> bool {
        self.debug
    }

    pub fn get_rpath(&self) -> bool {
        self.rpath
    }

    pub fn get_env(&self) -> &str {
        self.env.as_slice()
    }

    pub fn get_dest(&self) -> Option<&str> {
        self.dest.as_ref().map(|d| d.as_slice())
    }

    pub fn opt_level(mut self, level: uint) -> Profile {
        self.opt_level = level;
        self
    }

    pub fn codegen_units(mut self, units: Option<uint>) -> Profile {
        self.codegen_units = units;
        self
    }

    pub fn debug(mut self, debug: bool) -> Profile {
        self.debug = debug;
        self
    }

    pub fn rpath(mut self, rpath: bool) -> Profile {
        self.rpath = rpath;
        self
    }

    pub fn test(mut self, test: bool) -> Profile {
        self.test = test;
        self
    }

    pub fn doctest(mut self, doctest: bool) -> Profile {
        self.doctest = doctest;
        self
    }

    pub fn doc(mut self, doc: bool) -> Profile {
        self.doc = doc;
        self
    }

    pub fn plugin(mut self, plugin: bool) -> Profile {
        self.plugin = plugin;
        self
    }

    pub fn harness(mut self, harness: bool) -> Profile {
        self.harness = harness;
        self
    }
}

impl<H: hash::Writer> hash::Hash<H> for Profile {
    fn hash(&self, into: &mut H) {
        // Be sure to match all fields explicitly, but ignore those not relevant
        // to the actual hash of a profile.
        let Profile {
            opt_level,
            codegen_units,
            debug,
            rpath,
            plugin,
            dest: ref dest,
            harness: harness,

            // test flags are separated by file, not by profile hash, and
            // env/doc also don't matter for the actual contents of the output
            // file, just where the output file is located.
            doc: _,
            env: _,
            test: _,
            doctest: _,
        } = *self;
        (opt_level, codegen_units, debug, rpath, plugin, dest, harness).hash(into)
    }
}

/// Informations about a binary, a library, an example, etc. that is part of the package.
#[deriving(Clone, Hash, PartialEq)]
pub struct Target {
    kind: TargetKind,
    name: String,
    src_path: Path,
    profile: Profile,
    metadata: Option<Metadata>,
}

#[deriving(Encodable)]
pub struct SerializedTarget {
    kind: Vec<&'static str>,
    name: String,
    src_path: String,
    profile: Profile,
    metadata: Option<Metadata>
}

impl<E, S: Encoder<E>> Encodable<S, E> for Target {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let kind = match self.kind {
            LibTarget(ref kinds) => kinds.iter().map(|k| k.crate_type()).collect(),
            BinTarget => vec!("bin"),
            ExampleTarget => vec!["example"],
        };

        SerializedTarget {
            kind: kind,
            name: self.name.clone(),
            src_path: self.src_path.display().to_string(),
            profile: self.profile.clone(),
            metadata: self.metadata.clone()
        }.encode(s)
    }
}

impl Show for Target {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}(name={}, path={}, profile={})", self.kind, self.name,
               self.src_path.display(), self.profile)
    }
}

impl Manifest {
    pub fn new(summary: Summary, targets: Vec<Target>,
               target_dir: Path, doc_dir: Path,
               build: Vec<String>, exclude: Vec<String>,
               metadata: ManifestMetadata) -> Manifest {
        Manifest {
            summary: summary,
            targets: targets,
            target_dir: target_dir,
            doc_dir: doc_dir,
            build: build,
            warnings: Vec::new(),
            exclude: exclude,
            metadata: metadata,
        }
    }

    pub fn get_summary(&self) -> &Summary {
        &self.summary
    }

    pub fn get_package_id(&self) -> &PackageId {
        self.get_summary().get_package_id()
    }

    pub fn get_name(&self) -> &str {
        self.get_package_id().get_name()
    }

    pub fn get_version(&self) -> &Version {
        self.get_summary().get_package_id().get_version()
    }

    pub fn get_dependencies(&self) -> &[Dependency] {
        self.get_summary().get_dependencies()
    }

    pub fn get_targets(&self) -> &[Target] {
        self.targets.as_slice()
    }

    pub fn get_target_dir(&self) -> &Path {
        &self.target_dir
    }

    pub fn get_doc_dir(&self) -> &Path {
        &self.doc_dir
    }

    pub fn get_build(&self) -> &[String] {
        self.build.as_slice()
    }

    pub fn add_warning(&mut self, s: String) {
        self.warnings.push(s)
    }

    pub fn get_warnings(&self) -> &[String] {
        self.warnings.as_slice()
    }

    pub fn get_exclude(&self) -> &[String] {
        self.exclude.as_slice()
    }

    pub fn get_metadata(&self) -> &ManifestMetadata { &self.metadata }

    pub fn set_summary(&mut self, summary: Summary) {
        self.summary = summary;
    }
}

impl Target {
    pub fn file_stem(&self) -> String {
        match self.metadata {
            Some(ref metadata) => format!("{}{}", self.name, metadata.extra_filename),
            None => self.name.clone()
        }
    }

    pub fn lib_target(name: &str, crate_targets: Vec<LibKind>,
                      src_path: &Path, profile: &Profile,
                      metadata: Metadata) -> Target {
        Target {
            kind: LibTarget(crate_targets),
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: Some(metadata)
        }
    }

    pub fn bin_target(name: &str, src_path: &Path, profile: &Profile,
                      metadata: Option<Metadata>) -> Target {
        Target {
            kind: BinTarget,
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: metadata,
        }
    }

    pub fn example_target(name: &str, src_path: &Path, profile: &Profile) -> Target {
        Target {
            kind: ExampleTarget,
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: None,
        }
    }

    pub fn test_target(name: &str, src_path: &Path,
                       profile: &Profile, metadata: Metadata) -> Target {
        Target {
            kind: BinTarget,
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: Some(metadata),
        }
    }

    pub fn bench_target(name: &str, src_path: &Path,
                        profile: &Profile, metadata: Metadata) -> Target {
        Target {
            kind: BinTarget,
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: Some(metadata),
        }
    }

    pub fn get_name(&self) -> &str {
        self.name.as_slice()
    }

    pub fn get_src_path(&self) -> &Path {
        &self.src_path
    }

    pub fn is_lib(&self) -> bool {
        match self.kind {
            LibTarget(_) => true,
            _ => false
        }
    }

    pub fn is_dylib(&self) -> bool {
        match self.kind {
            LibTarget(ref kinds) => kinds.iter().any(|&k| k == Dylib),
            _ => false
        }
    }

    pub fn is_rlib(&self) -> bool {
        match self.kind {
            LibTarget(ref kinds) =>
                kinds.iter().any(|&k| k == Rlib || k == Lib),
            _ => false
        }
    }

    pub fn is_staticlib(&self) -> bool {
        match self.kind {
            LibTarget(ref kinds) => kinds.iter().any(|&k| k == StaticLib),
            _ => false
        }
    }

    /// Returns true for binary, bench, and tests.
    pub fn is_bin(&self) -> bool {
        match self.kind {
            BinTarget => true,
            _ => false
        }
    }

    /// Returns true for exampels
    pub fn is_example(&self) -> bool {
        match self.kind {
            ExampleTarget => true,
            _ => false
        }
    }

    pub fn get_profile(&self) -> &Profile {
        &self.profile
    }

    pub fn get_metadata(&self) -> Option<&Metadata> {
        self.metadata.as_ref()
    }

    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
    pub fn rustc_crate_types(&self) -> Vec<&'static str> {
        match self.kind {
            LibTarget(ref kinds) => {
                kinds.iter().map(|kind| kind.crate_type()).collect()
            },
            ExampleTarget |
            BinTarget => vec!("bin"),
        }
    }
}
<commit_msg>auto merge of #765 : steveklabnik/cargo/fix_warnings, r=alexcrichton<commit_after>use std::hash;
use std::fmt::{mod, Show, Formatter};

use semver::Version;
use serialize::{Encoder,Encodable};

use core::{Dependency, PackageId, Summary};
use core::package_id::Metadata;
use core::dependency::SerializedDependency;
use util::{CargoResult, human};

/// Contains all the informations about a package, as loaded from a Cargo.toml.
#[deriving(PartialEq,Clone)]
pub struct Manifest {
    summary: Summary,
    targets: Vec<Target>,
    target_dir: Path,
    doc_dir: Path,
    build: Vec<String>,
    warnings: Vec<String>,
    exclude: Vec<String>,
    metadata: ManifestMetadata,
}

impl Show for Manifest {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Manifest({}, targets={}, target_dir={}, \
                   build={})",
               self.summary, self.targets, self.target_dir.display(),
               self.build)
    }
}

/// General metadata about a package which is just blindly uploaded to the
/// registry.
///
/// Note that many of these fields can contain invalid values such as the
/// homepage, repository, documentation, or license. These fields are not
/// validated by cargo itself, but rather it is up to the registry when uploaded
/// to validate these fields. Cargo will itself accept any valid TOML
/// specification for these values.
#[deriving(PartialEq, Clone)]
pub struct ManifestMetadata {
    pub authors: Vec<String>,
    pub keywords: Vec<String>,
    pub license: Option<String>,
    pub description: Option<String>,    // not markdown
    pub readme: Option<String>,         // file, not contents
    pub homepage: Option<String>,       // url
    pub repository: Option<String>,     // url
    pub documentation: Option<String>,  // url
}

#[deriving(PartialEq,Clone,Encodable)]
pub struct SerializedManifest {
    name: String,
    version: String,
    dependencies: Vec<SerializedDependency>,
    targets: Vec<Target>,
    target_dir: String,
    doc_dir: String,
    build: Option<Vec<String>>,
}

impl<E, S: Encoder<E>> Encodable<S, E> for Manifest {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        SerializedManifest {
            name: self.summary.get_name().to_string(),
            version: self.summary.get_version().to_string(),
            dependencies: self.summary.get_dependencies().iter().map(|d| {
                SerializedDependency::from_dependency(d)
            }).collect(),
            targets: self.targets.clone(),
            target_dir: self.target_dir.display().to_string(),
            doc_dir: self.doc_dir.display().to_string(),
            build: if self.build.len() == 0 { None } else { Some(self.build.clone()) },
        }.encode(s)
    }
}

#[deriving(Show, Clone, PartialEq, Hash, Encodable)]
pub enum LibKind {
    Lib,
    Rlib,
    Dylib,
    StaticLib
}

impl LibKind {
    pub fn from_str(string: &str) -> CargoResult<LibKind> {
        match string {
            "lib" => Ok(Lib),
            "rlib" => Ok(Rlib),
            "dylib" => Ok(Dylib),
            "staticlib" => Ok(StaticLib),
            _ => Err(human(format!("{} was not one of lib|rlib|dylib|staticlib",
                                   string)))
        }
    }

    pub fn from_strs<S: Str>(strings: Vec<S>) -> CargoResult<Vec<LibKind>> {
        strings.iter().map(|s| LibKind::from_str(s.as_slice())).collect()
    }

    /// Returns the argument suitable for `--crate-type` to pass to rustc.
    pub fn crate_type(&self) -> &'static str {
        match *self {
            Lib => "lib",
            Rlib => "rlib",
            Dylib => "dylib",
            StaticLib => "staticlib"
        }
    }
}

#[deriving(Show, Clone, Hash, PartialEq, Encodable)]
pub enum TargetKind {
    LibTarget(Vec<LibKind>),
    BinTarget,
    ExampleTarget,
}

#[deriving(Encodable, Decodable, Clone, PartialEq, Show)]
pub struct Profile {
    env: String, // compile, test, dev, bench, etc.
    opt_level: uint,
    codegen_units: Option<uint>,    // None = use rustc default
    debug: bool,
    rpath: bool,
    test: bool,
    doctest: bool,
    doc: bool,
    dest: Option<String>,
    plugin: bool,
    harness: bool, // whether to use the test harness (--test)
}

impl Profile {
    fn default() -> Profile {
        Profile {
            env: String::new(),
            opt_level: 0,
            codegen_units: None,
            debug: false,
            rpath: false,
            test: false,
            doc: false,
            dest: None,
            plugin: false,
            doctest: false,
            harness: true,
        }
    }

    pub fn default_dev() -> Profile {
        Profile {
            env: "compile".to_string(), // run in the default environment only
            opt_level: 0,
            debug: true,
            .. Profile::default()
        }
    }

    pub fn default_test() -> Profile {
        Profile {
            env: "test".to_string(),
            debug: true,
            test: true,
            dest: None,
            .. Profile::default()
        }
    }

    pub fn default_bench() -> Profile {
        Profile {
            env: "bench".to_string(),
            opt_level: 3,
            test: true,
            dest: Some("release".to_string()),
            .. Profile::default()
        }
    }

    pub fn default_release() -> Profile {
        Profile {
            env: "release".to_string(),
            opt_level: 3,
            dest: Some("release".to_string()),
            .. Profile::default()
        }
    }

    pub fn default_doc() -> Profile {
        Profile {
            env: "doc".to_string(),
            dest: None,
            doc: true,
            .. Profile::default()
        }
    }

    pub fn is_compile(&self) -> bool {
        self.env.as_slice() == "compile"
    }

    pub fn is_doc(&self) -> bool {
        self.doc
    }

    pub fn is_test(&self) -> bool {
        self.test
    }

    pub fn uses_test_harness(&self) -> bool {
        self.harness
    }

    pub fn is_doctest(&self) -> bool {
        self.doctest
    }

    pub fn is_plugin(&self) -> bool {
        self.plugin
    }

    pub fn get_opt_level(&self) -> uint {
        self.opt_level
    }

    pub fn get_codegen_units(&self) -> Option<uint> {
        self.codegen_units
    }

    pub fn get_debug(&self) -> bool {
        self.debug
    }

    pub fn get_rpath(&self) -> bool {
        self.rpath
    }

    pub fn get_env(&self) -> &str {
        self.env.as_slice()
    }

    pub fn get_dest(&self) -> Option<&str> {
        self.dest.as_ref().map(|d| d.as_slice())
    }

    pub fn opt_level(mut self, level: uint) -> Profile {
        self.opt_level = level;
        self
    }

    pub fn codegen_units(mut self, units: Option<uint>) -> Profile {
        self.codegen_units = units;
        self
    }

    pub fn debug(mut self, debug: bool) -> Profile {
        self.debug = debug;
        self
    }

    pub fn rpath(mut self, rpath: bool) -> Profile {
        self.rpath = rpath;
        self
    }

    pub fn test(mut self, test: bool) -> Profile {
        self.test = test;
        self
    }

    pub fn doctest(mut self, doctest: bool) -> Profile {
        self.doctest = doctest;
        self
    }

    pub fn doc(mut self, doc: bool) -> Profile {
        self.doc = doc;
        self
    }

    pub fn plugin(mut self, plugin: bool) -> Profile {
        self.plugin = plugin;
        self
    }

    pub fn harness(mut self, harness: bool) -> Profile {
        self.harness = harness;
        self
    }
}

impl<H: hash::Writer> hash::Hash<H> for Profile {
    fn hash(&self, into: &mut H) {
        // Be sure to match all fields explicitly, but ignore those not relevant
        // to the actual hash of a profile.
        let Profile {
            opt_level,
            codegen_units,
            debug,
            rpath,
            plugin,
            ref dest,
            harness,

            // test flags are separated by file, not by profile hash, and
            // env/doc also don't matter for the actual contents of the output
            // file, just where the output file is located.
            doc: _,
            env: _,
            test: _,
            doctest: _,
        } = *self;
        (opt_level, codegen_units, debug, rpath, plugin, dest, harness).hash(into)
    }
}

/// Informations about a binary, a library, an example, etc. that is part of the package.
#[deriving(Clone, Hash, PartialEq)]
pub struct Target {
    kind: TargetKind,
    name: String,
    src_path: Path,
    profile: Profile,
    metadata: Option<Metadata>,
}

#[deriving(Encodable)]
pub struct SerializedTarget {
    kind: Vec<&'static str>,
    name: String,
    src_path: String,
    profile: Profile,
    metadata: Option<Metadata>
}

impl<E, S: Encoder<E>> Encodable<S, E> for Target {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let kind = match self.kind {
            LibTarget(ref kinds) => kinds.iter().map(|k| k.crate_type()).collect(),
            BinTarget => vec!("bin"),
            ExampleTarget => vec!["example"],
        };

        SerializedTarget {
            kind: kind,
            name: self.name.clone(),
            src_path: self.src_path.display().to_string(),
            profile: self.profile.clone(),
            metadata: self.metadata.clone()
        }.encode(s)
    }
}

impl Show for Target {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}(name={}, path={}, profile={})", self.kind, self.name,
               self.src_path.display(), self.profile)
    }
}

impl Manifest {
    pub fn new(summary: Summary, targets: Vec<Target>,
               target_dir: Path, doc_dir: Path,
               build: Vec<String>, exclude: Vec<String>,
               metadata: ManifestMetadata) -> Manifest {
        Manifest {
            summary: summary,
            targets: targets,
            target_dir: target_dir,
            doc_dir: doc_dir,
            build: build,
            warnings: Vec::new(),
            exclude: exclude,
            metadata: metadata,
        }
    }

    pub fn get_summary(&self) -> &Summary {
        &self.summary
    }

    pub fn get_package_id(&self) -> &PackageId {
        self.get_summary().get_package_id()
    }

    pub fn get_name(&self) -> &str {
        self.get_package_id().get_name()
    }

    pub fn get_version(&self) -> &Version {
        self.get_summary().get_package_id().get_version()
    }

    pub fn get_dependencies(&self) -> &[Dependency] {
        self.get_summary().get_dependencies()
    }

    pub fn get_targets(&self) -> &[Target] {
        self.targets.as_slice()
    }

    pub fn get_target_dir(&self) -> &Path {
        &self.target_dir
    }

    pub fn get_doc_dir(&self) -> &Path {
        &self.doc_dir
    }

    pub fn get_build(&self) -> &[String] {
        self.build.as_slice()
    }

    pub fn add_warning(&mut self, s: String) {
        self.warnings.push(s)
    }

    pub fn get_warnings(&self) -> &[String] {
        self.warnings.as_slice()
    }

    pub fn get_exclude(&self) -> &[String] {
        self.exclude.as_slice()
    }

    pub fn get_metadata(&self) -> &ManifestMetadata { &self.metadata }

    pub fn set_summary(&mut self, summary: Summary) {
        self.summary = summary;
    }
}

impl Target {
    pub fn file_stem(&self) -> String {
        match self.metadata {
            Some(ref metadata) => format!("{}{}", self.name, metadata.extra_filename),
            None => self.name.clone()
        }
    }

    pub fn lib_target(name: &str, crate_targets: Vec<LibKind>,
                      src_path: &Path, profile: &Profile,
                      metadata: Metadata) -> Target {
        Target {
            kind: LibTarget(crate_targets),
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: Some(metadata)
        }
    }

    pub fn bin_target(name: &str, src_path: &Path, profile: &Profile,
                      metadata: Option<Metadata>) -> Target {
        Target {
            kind: BinTarget,
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: metadata,
        }
    }

    pub fn example_target(name: &str, src_path: &Path, profile: &Profile) -> Target {
        Target {
            kind: ExampleTarget,
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: None,
        }
    }

    pub fn test_target(name: &str, src_path: &Path,
                       profile: &Profile, metadata: Metadata) -> Target {
        Target {
            kind: BinTarget,
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: Some(metadata),
        }
    }

    pub fn bench_target(name: &str, src_path: &Path,
                        profile: &Profile, metadata: Metadata) -> Target {
        Target {
            kind: BinTarget,
            name: name.to_string(),
            src_path: src_path.clone(),
            profile: profile.clone(),
            metadata: Some(metadata),
        }
    }

    pub fn get_name(&self) -> &str {
        self.name.as_slice()
    }

    pub fn get_src_path(&self) -> &Path {
        &self.src_path
    }

    pub fn is_lib(&self) -> bool {
        match self.kind {
            LibTarget(_) => true,
            _ => false
        }
    }

    pub fn is_dylib(&self) -> bool {
        match self.kind {
            LibTarget(ref kinds) => kinds.iter().any(|&k| k == Dylib),
            _ => false
        }
    }

    pub fn is_rlib(&self) -> bool {
        match self.kind {
            LibTarget(ref kinds) =>
                kinds.iter().any(|&k| k == Rlib || k == Lib),
            _ => false
        }
    }

    pub fn is_staticlib(&self) -> bool {
        match self.kind {
            LibTarget(ref kinds) => kinds.iter().any(|&k| k == StaticLib),
            _ => false
        }
    }

    /// Returns true for binary, bench, and tests.
    pub fn is_bin(&self) -> bool {
        match self.kind {
            BinTarget => true,
            _ => false
        }
    }

    /// Returns true for exampels
    pub fn is_example(&self) -> bool {
        match self.kind {
            ExampleTarget => true,
            _ => false
        }
    }

    pub fn get_profile(&self) -> &Profile {
        &self.profile
    }

    pub fn get_metadata(&self) -> Option<&Metadata> {
        self.metadata.as_ref()
    }

    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
    pub fn rustc_crate_types(&self) -> Vec<&'static str> {
        match self.kind {
            LibTarget(ref kinds) => {
                kinds.iter().map(|kind| kind.crate_type()).collect()
            },
            ExampleTarget |
            BinTarget => vec!("bin"),
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::hash::Hash;

pub trait Data : Eq + Hash {
    fn distance_to(&self, other: &Self) -> u64;
    fn mean_of(data_and_counts: &Vec<Node<Self>>) -> Self;
}

pub struct Node<T: Data> {
    pub data: T,
    pub count: u32,
}

pub fn quantize<I>(items: I) -> HashMap<I::Item, I::Item>
    where I: Iterator,
          I::Item: Data {

    let mut count_of_items: HashMap<I::Item, u32> = HashMap::new();

    for item in items {
        let counter = count_of_items.entry(item).or_insert(0);
        *counter += 1;
    }

    count_of_items.shrink_to_fit();

    println!("{:?}", count_of_items.len());

    let mut quantization_map = HashMap::new();
    quantization_map
}
<commit_msg>Added centroid struct, made nodes and centroids initialization functions.<commit_after>use std::collections::HashMap;
use std::hash::Hash;

pub trait Data : Eq + Hash + Copy + Clone {
    fn distance_to(&self, other: &Self) -> u64;
    fn mean_of(data_and_counts: &Vec<Node<Self>>) -> Self;
}

pub struct Node<T: Data> {
    pub data: T,
    pub count: u32,
}

impl<T: Data> Node<T> {
    fn to_centroid(&self) -> Centroid<T> {
        Centroid { data: self.data }
    }
}

struct Centroid<T: Data> {
    data: T,
}

pub fn quantize<I>(items: I) -> HashMap<I::Item, I::Item>
    where I: Iterator,
          I::Item: Data {
    let k = 256;

    let nodes = create_nodes(items);
    let mut centroids = initialize_centroids(k, &nodes);

    println!("{:?}", nodes.len());
    println!("{:?}", centroids.len());

    let mut quantization_map = HashMap::new();
    quantization_map
}

fn create_nodes<I>(items: I) -> Vec<Node<I::Item>>
    where I: Iterator,
          I::Item: Data {

    let mut count_of_items: HashMap<I::Item, u32> = HashMap::new();
    for item in items {
        let counter = count_of_items.entry(item).or_insert(0);
        *counter += 1;
    }

    let mut nodes = Vec::with_capacity(count_of_items.len());
    for (item, count) in count_of_items {
        nodes.push(Node { data: item, count: count });
    }
    nodes
}

fn initialize_centroids<T: Data>(k: usize, nodes: &Vec<Node<T>>) -> Vec<Centroid<T>> {
    nodes.iter().take(k).map(|node| { node.to_centroid() }).collect()
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::ops::DerefMut;
use std::cmp;

use game::*;
use game::data::*;
use ecs::*;
use behaviour::LeafResolution;
use direction::{self, Direction};

pub fn player_input<K: KnowledgeRenderer, I: 'static + InputSource + Clone>(input_source: I) -> BehaviourLeaf<K> {
    BehaviourLeaf::new(move |input| {
        loop {
            if let Some(meta_action) = get_meta_action(input, input_source.clone()) {
                return LeafResolution::Yield(meta_action);
            }
        }
    })
}

fn get_direction<I: InputSource>(map: &ControlMap, mut input_source: I) -> Option<Direction> {
    input_source.next_input().and_then(|event| {
        map.get(event).and_then(|control| {
            control_to_direction(control)
        })
    })
}

fn control_to_direction(control: Control) -> Option<Direction> {
    match control {
        Control::Direction(d) => Some(d),
        _ => None,
    }
}

fn display_message_log<K: KnowledgeRenderer, I: InputSource>(input: BehaviourInput<K>, mut input_source: I, map: &ControlMap) {

    let mut renderer = input.renderer.borrow_mut();
    let message_log = input.entity.message_log_borrow().unwrap();

    let mut offset = 0;
    let num_lines = renderer.fullscreen_log_num_rows();
    let num_messages = message_log.len();
    let max_offset = if num_messages > num_lines {
        num_messages - num_lines
    } else {
        0
    };

    loop {
        renderer.publish_fullscreen_log(message_log.deref(), offset, input.language);

        if let Some(event) = input_source.next_input() {
            if let Some(control) = map.get(event) {
                match control {
                    Control::Pause |
                        Control::DisplayMessageLog => break,
                    Control::Direction(Direction::North) => {
                        offset = cmp::min(max_offset, offset + 1);
                    }
                    Control::Direction(Direction::South) => {
                        if offset > 0 {
                            offset -= 1;
                        }
                    }
                    _ => {}
                }
            }
        }
    }

    renderer.publish_all_windows(input.entity, input.language);
}

fn aim<R: KnowledgeRenderer, I: InputSource>(input: BehaviourInput<R>, map: &ControlMap, mut input_source: I) -> Option<(EntityId, Direction)> {

    let mut renderer = input.renderer.borrow_mut();
    let mut message_log = input.entity.message_log_borrow_mut().expect("Expected component message_log");

    message_log.add_temporary(MessageType::ChooseDirection);
    renderer.update_log_buffer(message_log.deref(), input.language);
    renderer.draw_log();
    renderer.publish();

    let mut should_clear_log = true;

    let ret = input_source.next_input().and_then(|event| {
        map.get(event).and_then(|control| {
            match control {
                Control::Direction(direction) => {
                    let weapon_slots = input.entity.weapon_slots_borrow().expect("Expected component weapon_slots");
                    if let Some(weapon) = weapon_slots.get(direction) {
                        Some((*weapon, direction))
                    } else {
                        message_log.add(MessageType::EmptyWeaponSlotMessage);
                        should_clear_log = false;
                        None
                    }
                }
                _ => None,
            }
        })
    });

    if should_clear_log {
        message_log.add_temporary(MessageType::Empty);
    }
    renderer.update_log_buffer(message_log.deref(), input.language);
    renderer.draw_log();
    renderer.publish();

    ret
}

fn direction_to_relative_message(direction: Direction) -> MessageType {
    match direction {
        Direction::East => MessageType::Front,
        Direction::West => MessageType::Rear,
        Direction::North => MessageType::Left,
        Direction::South => MessageType::Right,
        _ => panic!(),
    }
}

fn display_status<K: KnowledgeRenderer, I: InputSource>(input: BehaviourInput<K>, mut input_source: I) {
    let mut renderer = input.renderer.borrow_mut();
    let weapon_slots = input.entity.weapon_slots_borrow().expect("Expected component weapon_slots");

    let mut message = Message::new();

    for d in direction::cardinal_direction_iter() {
        let m = direction_to_relative_message(d);
        input.language.translate(m, &mut message);
        message.push(MessagePart::plain(": "));

        if let Some(weapon_id) = weapon_slots.get(d) {
            let name = input.ecs.name(*weapon_id).expect("Expected component name");
            input.language.translate(MessageType::Name(name), &mut message);
        } else {
            input.language.translate(MessageType::EmptyWeaponSlot, &mut message);
        }
        message.push(MessagePart::Newline);
    }

    display_message_scrolling(renderer.deref_mut(), &mut input_source, &message, true);
    renderer.publish_all_windows(input.entity, input.language);
}

fn get_meta_action<K: KnowledgeRenderer, I: InputSource>(input: BehaviourInput<K>, mut input_source: I) -> Option<MetaAction> {
    input_source.next_input().and_then(|event| {
        if event == InputEvent::Quit {
            return Some(MetaAction::External(External::Quit));
        }
        input.entity.control_map_borrow().and_then(|map_ref| {
            let map = map_ref.deref();
            map.get(event).and_then(|control| {
                match control {
                    Control::Direction(Direction::East) => Some(MetaAction::ActionArgs(ActionArgs::ChangeSpeed(input.entity.id(), ChangeSpeed::Accelerate))),
                    Control::Direction(Direction::West) => Some(MetaAction::ActionArgs(ActionArgs::ChangeSpeed(input.entity.id(), ChangeSpeed::Decelerate))),
                    Control::Direction(Direction::North) => Some(MetaAction::ActionArgs(ActionArgs::Steer(input.entity.id(), SteerDirection::Up))),
                    Control::Direction(Direction::South) => Some(MetaAction::ActionArgs(ActionArgs::Steer(input.entity.id(), SteerDirection::Down))),
                    Control::Fire => {
                        aim(input, map, input_source).map(|(gun_id, direction)| {
                            MetaAction::ActionArgs(ActionArgs::FireGun {
                                gun_id: gun_id,
                                shooter_id: input.entity.id(),
                                direction: direction,
                            })
                        })
                    }
                    Control::Wait => {
                        Some(MetaAction::ActionArgs(ActionArgs::Null))
                    }
                    Control::Pause => Some(MetaAction::External(External::Pause)),
                    Control::DisplayMessageLog => {
                        display_message_log(input, input_source, map);
                        None
                    }
                    Control::Status => {
                        display_status(input, input_source);
                        None
                    }
                    _ => None,
                }
            })
        })
    })
}
<commit_msg>Remove lingering message about no weapon in slot<commit_after>use std::ops::Deref;
use std::ops::DerefMut;
use std::cmp;

use game::*;
use game::data::*;
use ecs::*;
use behaviour::LeafResolution;
use direction::{self, Direction};

pub fn player_input<K: KnowledgeRenderer, I: 'static + InputSource + Clone>(input_source: I) -> BehaviourLeaf<K> {
    BehaviourLeaf::new(move |input| {
        loop {
            if let Some(meta_action) = get_meta_action(input, input_source.clone()) {
                return LeafResolution::Yield(meta_action);
            }
        }
    })
}

fn get_direction<I: InputSource>(map: &ControlMap, mut input_source: I) -> Option<Direction> {
    input_source.next_input().and_then(|event| {
        map.get(event).and_then(|control| {
            control_to_direction(control)
        })
    })
}

fn control_to_direction(control: Control) -> Option<Direction> {
    match control {
        Control::Direction(d) => Some(d),
        _ => None,
    }
}

fn display_message_log<K: KnowledgeRenderer, I: InputSource>(input: BehaviourInput<K>, mut input_source: I, map: &ControlMap) {

    let mut renderer = input.renderer.borrow_mut();
    let message_log = input.entity.message_log_borrow().unwrap();

    let mut offset = 0;
    let num_lines = renderer.fullscreen_log_num_rows();
    let num_messages = message_log.len();
    let max_offset = if num_messages > num_lines {
        num_messages - num_lines
    } else {
        0
    };

    loop {
        renderer.publish_fullscreen_log(message_log.deref(), offset, input.language);

        if let Some(event) = input_source.next_input() {
            if let Some(control) = map.get(event) {
                match control {
                    Control::Pause |
                        Control::DisplayMessageLog => break,
                    Control::Direction(Direction::North) => {
                        offset = cmp::min(max_offset, offset + 1);
                    }
                    Control::Direction(Direction::South) => {
                        if offset > 0 {
                            offset -= 1;
                        }
                    }
                    _ => {}
                }
            }
        }
    }

    renderer.publish_all_windows(input.entity, input.language);
}

fn aim<R: KnowledgeRenderer, I: InputSource>(input: BehaviourInput<R>, map: &ControlMap, mut input_source: I) -> Option<(EntityId, Direction)> {

    let mut renderer = input.renderer.borrow_mut();
    let mut message_log = input.entity.message_log_borrow_mut().expect("Expected component message_log");

    message_log.add_temporary(MessageType::ChooseDirection);
    renderer.update_log_buffer(message_log.deref(), input.language);
    renderer.draw_log();
    renderer.publish();

    let mut should_clear_log = true;

    let ret = input_source.next_input().and_then(|event| {
        map.get(event).and_then(|control| {
            match control {
                Control::Direction(direction) => {
                    let weapon_slots = input.entity.weapon_slots_borrow().expect("Expected component weapon_slots");
                    if let Some(weapon) = weapon_slots.get(direction) {
                        Some((*weapon, direction))
                    } else {
                        message_log.add_temporary(MessageType::EmptyWeaponSlotMessage);
                        should_clear_log = false;
                        None
                    }
                }
                _ => None,
            }
        })
    });

    if should_clear_log {
        message_log.add_temporary(MessageType::Empty);
    }
    renderer.update_log_buffer(message_log.deref(), input.language);
    renderer.draw_log();
    renderer.publish();

    ret
}

fn direction_to_relative_message(direction: Direction) -> MessageType {
    match direction {
        Direction::East => MessageType::Front,
        Direction::West => MessageType::Rear,
        Direction::North => MessageType::Left,
        Direction::South => MessageType::Right,
        _ => panic!(),
    }
}

fn display_status<K: KnowledgeRenderer, I: InputSource>(input: BehaviourInput<K>, mut input_source: I) {
    let mut renderer = input.renderer.borrow_mut();
    let weapon_slots = input.entity.weapon_slots_borrow().expect("Expected component weapon_slots");

    let mut message = Message::new();

    for d in direction::cardinal_direction_iter() {
        let m = direction_to_relative_message(d);
        input.language.translate(m, &mut message);
        message.push(MessagePart::plain(": "));

        if let Some(weapon_id) = weapon_slots.get(d) {
            let name = input.ecs.name(*weapon_id).expect("Expected component name");
            input.language.translate(MessageType::Name(name), &mut message);
        } else {
            input.language.translate(MessageType::EmptyWeaponSlot, &mut message);
        }
        message.push(MessagePart::Newline);
    }

    display_message_scrolling(renderer.deref_mut(), &mut input_source, &message, true);
    renderer.publish_all_windows(input.entity, input.language);
}

fn get_meta_action<K: KnowledgeRenderer, I: InputSource>(input: BehaviourInput<K>, mut input_source: I) -> Option<MetaAction> {

    // clear temporary messages from the log
    input.entity.message_log_borrow_mut().expect("Expected component message_log").add_temporary(MessageType::Empty);

    input_source.next_input().and_then(|event| {
        if event == InputEvent::Quit {
            return Some(MetaAction::External(External::Quit));
        }
        input.entity.control_map_borrow().and_then(|map_ref| {
            let map = map_ref.deref();
            map.get(event).and_then(|control| {
                match control {
                    Control::Direction(Direction::East) => Some(MetaAction::ActionArgs(ActionArgs::ChangeSpeed(input.entity.id(), ChangeSpeed::Accelerate))),
                    Control::Direction(Direction::West) => Some(MetaAction::ActionArgs(ActionArgs::ChangeSpeed(input.entity.id(), ChangeSpeed::Decelerate))),
                    Control::Direction(Direction::North) => Some(MetaAction::ActionArgs(ActionArgs::Steer(input.entity.id(), SteerDirection::Up))),
                    Control::Direction(Direction::South) => Some(MetaAction::ActionArgs(ActionArgs::Steer(input.entity.id(), SteerDirection::Down))),
                    Control::Fire => {
                        aim(input, map, input_source).map(|(gun_id, direction)| {
                            MetaAction::ActionArgs(ActionArgs::FireGun {
                                gun_id: gun_id,
                                shooter_id: input.entity.id(),
                                direction: direction,
                            })
                        })
                    }
                    Control::Wait => {
                        Some(MetaAction::ActionArgs(ActionArgs::Null))
                    }
                    Control::Pause => Some(MetaAction::External(External::Pause)),
                    Control::DisplayMessageLog => {
                        display_message_log(input, input_source, map);
                        None
                    }
                    Control::Status => {
                        display_status(input, input_source);
                        None
                    }
                    _ => None,
                }
            })
        })
    })
}
<|endoftext|>


<commit_before>use client::AsyncClient;
use dovahkiin::types::custom_types::id::Id;
use index;
use index::lsmtree::cursor::LSMTreeCursor;
use index::lsmtree::placement::sm::client::SMClient;
use index::lsmtree::split::check_and_split;
use index::lsmtree::tree::LSMTree;
use index::lsmtree::tree::{KeyRange, LSMTreeResult};
use index::Cursor;
use index::EntryKey;
use linked_hash_map::LinkedHashMap;
use parking_lot::Mutex;
use parking_lot::MutexGuard;
use ram::clock;
use server::NebServer;
use std::cell::RefCell;
use std::cell::RefMut;
use std::collections::btree_map::BTreeMap;
use std::collections::hash_map::Entry;
use std::rc::Rc;
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;

const CURSOR_DEFAULT_TTL: u32 = 5 * 60 * 1000;

struct DelegatedCursor {
    cursor: MutCursorRef,
    timestamp: u32,
}

type CursorMap = LinkedHashMap<u64, DelegatedCursor>;
type MutCursorRef = Rc<RefCell<LSMTreeCursor>>;

pub struct LSMTreeIns {
    pub tree: LSMTree,
    counter: AtomicU64,
    cursors: Mutex<CursorMap>,
}

impl DelegatedCursor {
    fn new(cursor: LSMTreeCursor) -> Self {
        let cursor = Rc::new(RefCell::new(cursor));
        let timestamp = clock::now();
        Self { cursor, timestamp }
    }
}

impl LSMTreeIns {
    pub fn new(range: KeyRange, id: Id) -> Self {
        Self::new_from_tree(LSMTree::new(range, id))
    }

    pub fn new_from_tree(tree: LSMTree) -> Self {
        Self {
            tree,
            counter: AtomicU64::new(0),
            cursors: Mutex::new(CursorMap::new()),
        }
    }

    fn get(&self, id: &u64) -> Option<MutCursorRef> {
        self.cursors.lock().get_refresh(id).map(|c| {
            c.timestamp = clock::now();
            c.cursor.clone()
        })
    }

    fn pop_expired_cursors(map: &mut MutexGuard<CursorMap>) {
        let mut expired_cursors = 0;
        while let Some((_, c)) = map.iter().next() {
            if c.timestamp + CURSOR_DEFAULT_TTL < clock::now() {
                expired_cursors += 1;
            } else {
                break;
            }
        }
        for _ in 0..expired_cursors {
            map.pop_front();
        }
    }

    pub fn seek(&self, key: &EntryKey, ordering: index::Ordering) -> u64 {
        let cursor = self.tree.seek(key, ordering);
        let mut map = self.cursors.lock();
        Self::pop_expired_cursors(&mut map);
        let id = self.counter.fetch_and(1, Ordering::Relaxed);
        map.insert(id, DelegatedCursor::new(cursor));
        return id;
    }

    pub fn next(&self, id: &u64) -> Option<bool> {
        self.get(id).map(|mut c| c.borrow_mut().next())
    }

    pub fn next_block(&self, id: &u64, block_size: usize) -> Option<Vec<Vec<u8>>> {
        self.get(id).map(|mut c| {
            let mut keys = Vec::with_capacity(block_size);
            let mut cursor = c.borrow_mut();
            let current = |cursor: &LSMTreeCursor| cursor.current().map(|k| k.as_slice().to_vec());
            if let Some(first_key) = current(&*cursor) {
                keys.push(first_key);
                while keys.len() < block_size && cursor.next() {
                    keys.push(current(&*cursor).unwrap());
                }
            }
            keys
        })
    }

    pub fn current(&self, id: &u64) -> Option<Option<Vec<u8>>> {
        self.get(id)
            .map(|c| c.borrow().current().map(|k| k.as_slice().to_vec()))
    }

    pub fn complete(&self, id: &u64) -> bool {
        self.cursors.lock().remove(id).is_some()
    }

    pub fn count(&self) -> u64 {
        self.tree.count() as u64
    }

    pub fn range(&self) -> (Vec<u8>, Vec<u8>) {
        let range = self.tree.range.lock();
        (range.0.clone().into_vec(), range.1.clone().into_vec())
    }

    pub fn check_and_merge(&self) {
        self.tree.check_and_merge()
    }

    pub fn oversized(&self) -> bool {
        self.tree.oversized()
    }

    pub fn insert(&self, key: EntryKey) -> bool {
        self.tree.insert(key)
    }

    pub fn with_epoch_check<F, T>(&self, epoch: u64, f: F) -> LSMTreeResult<T>
    where
        F: FnOnce() -> T,
    {
        let tree_epoch = self.tree.epoch();
        if tree_epoch != epoch {
            LSMTreeResult::EpochMismatch(tree_epoch, epoch)
        } else {
            LSMTreeResult::Ok(f())
        }
    }

    pub fn epoch(&self) -> u64 {
        self.tree.epoch()
    }

    pub fn merge(&self, keys: Box<Vec<EntryKey>>) {
        self.tree.merge(keys)
    }

    pub fn remove_to_right(&self, start_key: &EntryKey) {
        self.tree.remove_to_right(start_key);
    }

    pub fn set_epoch(&self, epoch: u64) {
        self.tree.set_epoch(epoch);
    }

    pub fn check_and_split(&self, sm: &Arc<SMClient>, neb: &Arc<NebServer>) -> Option<usize> {
        check_and_split(&self.tree, sm, neb)
    }
}

unsafe impl Send for LSMTreeIns {}
unsafe impl Sync for LSMTreeIns {}
<commit_msg>reorder checker<commit_after>use client::AsyncClient;
use dovahkiin::types::custom_types::id::Id;
use index;
use index::lsmtree::cursor::LSMTreeCursor;
use index::lsmtree::placement::sm::client::SMClient;
use index::lsmtree::split::check_and_split;
use index::lsmtree::tree::LSMTree;
use index::lsmtree::tree::{KeyRange, LSMTreeResult};
use index::Cursor;
use index::EntryKey;
use linked_hash_map::LinkedHashMap;
use parking_lot::Mutex;
use parking_lot::MutexGuard;
use ram::clock;
use server::NebServer;
use std::cell::RefCell;
use std::cell::RefMut;
use std::collections::btree_map::BTreeMap;
use std::collections::hash_map::Entry;
use std::rc::Rc;
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;

const CURSOR_DEFAULT_TTL: u32 = 5 * 60 * 1000;

struct DelegatedCursor {
    cursor: MutCursorRef,
    timestamp: u32,
}

type CursorMap = LinkedHashMap<u64, DelegatedCursor>;
type MutCursorRef = Rc<RefCell<LSMTreeCursor>>;

pub struct LSMTreeIns {
    pub tree: LSMTree,
    counter: AtomicU64,
    cursors: Mutex<CursorMap>,
}

impl DelegatedCursor {
    fn new(cursor: LSMTreeCursor) -> Self {
        let cursor = Rc::new(RefCell::new(cursor));
        let timestamp = clock::now();
        Self { cursor, timestamp }
    }
}

impl LSMTreeIns {
    pub fn new(range: KeyRange, id: Id) -> Self {
        Self::new_from_tree(LSMTree::new(range, id))
    }

    pub fn new_from_tree(tree: LSMTree) -> Self {
        Self {
            tree,
            counter: AtomicU64::new(0),
            cursors: Mutex::new(CursorMap::new()),
        }
    }

    fn get(&self, id: &u64) -> Option<MutCursorRef> {
        self.cursors.lock().get_refresh(id).map(|c| {
            c.timestamp = clock::now();
            c.cursor.clone()
        })
    }

    fn pop_expired_cursors(map: &mut MutexGuard<CursorMap>) {
        let mut expired_cursors = 0;
        while let Some((_, c)) = map.iter().next() {
            if c.timestamp + CURSOR_DEFAULT_TTL < clock::now() {
                expired_cursors += 1;
            } else {
                break;
            }
        }
        for _ in 0..expired_cursors {
            map.pop_front();
        }
    }

    pub fn seek(&self, key: &EntryKey, ordering: index::Ordering) -> u64 {
        let cursor = self.tree.seek(key, ordering);
        let mut map = self.cursors.lock();
        Self::pop_expired_cursors(&mut map);
        let id = self.counter.fetch_and(1, Ordering::Relaxed);
        map.insert(id, DelegatedCursor::new(cursor));
        return id;
    }

    pub fn next(&self, id: &u64) -> Option<bool> {
        self.get(id).map(|mut c| c.borrow_mut().next())
    }

    pub fn next_block(&self, id: &u64, block_size: usize) -> Option<Vec<Vec<u8>>> {
        self.get(id).map(|mut c| {
            let mut keys = Vec::with_capacity(block_size);
            let mut cursor = c.borrow_mut();
            let current = |cursor: &LSMTreeCursor| cursor.current().map(|k| k.as_slice().to_vec());
            if let Some(first_key) = current(&*cursor) {
                keys.push(first_key);
                while cursor.next() && keys.len() < block_size {
                    keys.push(current(&*cursor).unwrap());
                }
            }
            keys
        })
    }

    pub fn current(&self, id: &u64) -> Option<Option<Vec<u8>>> {
        self.get(id)
            .map(|c| c.borrow().current().map(|k| k.as_slice().to_vec()))
    }

    pub fn complete(&self, id: &u64) -> bool {
        self.cursors.lock().remove(id).is_some()
    }

    pub fn count(&self) -> u64 {
        self.tree.count() as u64
    }

    pub fn range(&self) -> (Vec<u8>, Vec<u8>) {
        let range = self.tree.range.lock();
        (range.0.clone().into_vec(), range.1.clone().into_vec())
    }

    pub fn check_and_merge(&self) {
        self.tree.check_and_merge()
    }

    pub fn oversized(&self) -> bool {
        self.tree.oversized()
    }

    pub fn insert(&self, key: EntryKey) -> bool {
        self.tree.insert(key)
    }

    pub fn with_epoch_check<F, T>(&self, epoch: u64, f: F) -> LSMTreeResult<T>
    where
        F: FnOnce() -> T,
    {
        let tree_epoch = self.tree.epoch();
        if tree_epoch != epoch {
            LSMTreeResult::EpochMismatch(tree_epoch, epoch)
        } else {
            LSMTreeResult::Ok(f())
        }
    }

    pub fn epoch(&self) -> u64 {
        self.tree.epoch()
    }

    pub fn merge(&self, keys: Box<Vec<EntryKey>>) {
        self.tree.merge(keys)
    }

    pub fn remove_to_right(&self, start_key: &EntryKey) {
        self.tree.remove_to_right(start_key);
    }

    pub fn set_epoch(&self, epoch: u64) {
        self.tree.set_epoch(epoch);
    }

    pub fn check_and_split(&self, sm: &Arc<SMClient>, neb: &Arc<NebServer>) -> Option<usize> {
        check_and_split(&self.tree, sm, neb)
    }
}

unsafe impl Send for LSMTreeIns {}
unsafe impl Sync for LSMTreeIns {}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::mem;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use types::Oid;
use util;

use self::BackendMessage::*;
use self::FrontendMessage::*;

pub const PROTOCOL_VERSION: u32 = 0x0003_0000;
pub const CANCEL_CODE: u32 = 80877102;
pub const SSL_CODE: u32 = 80877103;

pub enum BackendMessage {
    AuthenticationCleartextPassword,
    AuthenticationGSS,
    AuthenticationKerberosV5,
    AuthenticationMD5Password {
        salt: [u8; 4]
    },
    AuthenticationOk,
    AuthenticationSCMCredential,
    AuthenticationSSPI,
    BackendKeyData {
        process_id: u32,
        secret_key: u32
    },
    BindComplete,
    CloseComplete,
    CommandComplete {
        tag: String,
    },
    CopyInResponse {
        format: u8,
        column_formats: Vec<u16>,
    },
    DataRow {
        row: Vec<Option<Vec<u8>>>
    },
    EmptyQueryResponse,
    ErrorResponse {
        fields: Vec<(u8, String)>
    },
    NoData,
    NoticeResponse {
        fields: Vec<(u8, String)>
    },
    NotificationResponse {
        pid: u32,
        channel: String,
        payload: String,
    },
    ParameterDescription {
        types: Vec<Oid>
    },
    ParameterStatus {
        parameter: String,
        value: String,
    },
    ParseComplete,
    PortalSuspended,
    ReadyForQuery {
        _state: u8
    },
    RowDescription {
        descriptions: Vec<RowDescriptionEntry>
    }
}

pub struct RowDescriptionEntry {
    pub name: String,
    pub table_oid: Oid,
    pub column_id: i16,
    pub type_oid: Oid,
    pub type_size: i16,
    pub type_modifier: i32,
    pub format: i16
}

pub enum FrontendMessage<'a> {
    Bind {
        portal: &'a str,
        statement: &'a str,
        formats: &'a [i16],
        values: &'a [Option<Vec<u8>>],
        result_formats: &'a [i16]
    },
    CancelRequest {
        code: u32,
        process_id: u32,
        secret_key: u32,
    },
    Close {
        variant: u8,
        name: &'a str
    },
    CopyData {
        data: &'a [u8],
    },
    CopyDone,
    CopyFail {
        message: &'a str
    },
    Describe {
        variant: u8,
        name: &'a str
    },
    Execute {
        portal: &'a str,
        max_rows: i32
    },
    Parse {
        name: &'a str,
        query: &'a str,
        param_types: &'a [Oid]
    },
    PasswordMessage {
        password: &'a str
    },
    Query {
        query: &'a str
    },
    SslRequest {
        code: u32
    },
    StartupMessage {
        version: u32,
        parameters: &'a [(String, String)]
    },
    Sync,
    Terminate
}

#[doc(hidden)]
trait WriteCStr {
    fn write_cstr(&mut self, s: &str) -> io::Result<()>;
}

impl<W: Write> WriteCStr for W {
    fn write_cstr(&mut self, s: &str) -> io::Result<()> {
        try!(self.write_all(s.as_bytes()));
        Ok(try!(self.write_u8(0)))
    }
}

#[doc(hidden)]
pub trait WriteMessage {
    fn write_message(&mut self, &FrontendMessage) -> io::Result<()> ;
}

impl<W: Write> WriteMessage for W {
    fn write_message(&mut self, message: &FrontendMessage) -> io::Result<()> {
        let mut buf = vec![];
        let mut ident = None;

        match *message {
            Bind { portal, statement, formats, values, result_formats } => {
                ident = Some(b'B');
                try!(buf.write_cstr(portal));
                try!(buf.write_cstr(statement));

                try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(formats.len()))));
                for &format in formats {
                    try!(buf.write_i16::<BigEndian>(format));
                }

                try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(values.len()))));
                for value in values {
                    match *value {
                        None => try!(buf.write_i32::<BigEndian>(-1)),
                        Some(ref value) => {
                            try!(buf.write_i32::<BigEndian>(try!(i32::from_usize(value.len()))));
                            try!(buf.write_all(&**value));
                        }
                    }
                }

                try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(result_formats.len()))));
                for &format in result_formats {
                    try!(buf.write_i16::<BigEndian>(format));
                }
            }
            CancelRequest { code, process_id, secret_key } => {
                try!(buf.write_u32::<BigEndian>(code));
                try!(buf.write_u32::<BigEndian>(process_id));
                try!(buf.write_u32::<BigEndian>(secret_key));
            }
            Close { variant, name } => {
                ident = Some(b'C');
                try!(buf.write_u8(variant));
                try!(buf.write_cstr(name));
            }
            CopyData { data } => {
                ident = Some(b'd');
                try!(buf.write_all(data));
            }
            CopyDone => ident = Some(b'c'),
            CopyFail { message } => {
                ident = Some(b'f');
                try!(buf.write_cstr(message));
            }
            Describe { variant, name } => {
                ident = Some(b'D');
                try!(buf.write_u8(variant));
                try!(buf.write_cstr(name));
            }
            Execute { portal, max_rows } => {
                ident = Some(b'E');
                try!(buf.write_cstr(portal));
                try!(buf.write_i32::<BigEndian>(max_rows));
            }
            Parse { name, query, param_types } => {
                ident = Some(b'P');
                try!(buf.write_cstr(name));
                try!(buf.write_cstr(query));
                try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(param_types.len()))));
                for &ty in param_types {
                    try!(buf.write_u32::<BigEndian>(ty));
                }
            }
            PasswordMessage { password } => {
                ident = Some(b'p');
                try!(buf.write_cstr(password));
            }
            Query { query } => {
                ident = Some(b'Q');
                try!(buf.write_cstr(query));
            }
            StartupMessage { version, parameters } => {
                try!(buf.write_u32::<BigEndian>(version));
                for &(ref k, ref v) in parameters {
                    try!(buf.write_cstr(&**k));
                    try!(buf.write_cstr(&**v));
                }
                try!(buf.write_u8(0));
            }
            SslRequest { code } => try!(buf.write_u32::<BigEndian>(code)),
            Sync => ident = Some(b'S'),
            Terminate => ident = Some(b'X'),
        }

        if let Some(ident) = ident {
            try!(self.write_u8(ident));
        }

        // add size of length value
        if buf.len() > u32::max_value() as usize - mem::size_of::<u32>() {
            return Err(io::Error::new(io::ErrorKind::InvalidInput, "value too large to transmit"));
        }
        try!(self.write_u32::<BigEndian>((buf.len() + mem::size_of::<u32>()) as u32));
        try!(self.write_all(&*buf));

        Ok(())
    }
}

#[doc(hidden)]
trait ReadCStr {
    fn read_cstr(&mut self) -> io::Result<String>;
}

impl<R: BufRead> ReadCStr for R {
    fn read_cstr(&mut self) -> io::Result<String> {
        let mut buf = vec![];
        try!(self.read_until(0, &mut buf));
        buf.pop();
        String::from_utf8(buf).map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

#[doc(hidden)]
pub trait ReadMessage {
    fn read_message(&mut self) -> io::Result<BackendMessage>;
}

impl<R: BufRead> ReadMessage for R {
    fn read_message(&mut self) -> io::Result<BackendMessage> {
        let ident = try!(self.read_u8());

        // subtract size of length value
        let len = try!(self.read_u32::<BigEndian>()) - mem::size_of::<u32>() as u32;
        let mut rdr = self.by_ref().take(len as u64);

        let ret = match ident {
            b'1' => ParseComplete,
            b'2' => BindComplete,
            b'3' => CloseComplete,
            b'A' => NotificationResponse {
                pid: try!(rdr.read_u32::<BigEndian>()),
                channel: try!(rdr.read_cstr()),
                payload: try!(rdr.read_cstr())
            },
            b'C' => CommandComplete { tag: try!(rdr.read_cstr()) },
            b'D' => try!(read_data_row(&mut rdr)),
            b'E' => ErrorResponse { fields: try!(read_fields(&mut rdr)) },
            b'G' => {
                let format = try!(rdr.read_u8());
                let mut column_formats = vec![];
                for _ in 0..try!(rdr.read_u16::<BigEndian>()) {
                    column_formats.push(try!(rdr.read_u16::<BigEndian>()));
                }
                CopyInResponse {
                    format: format,
                    column_formats: column_formats,
                }
            }
            b'I' => EmptyQueryResponse,
            b'K' => BackendKeyData {
                process_id: try!(rdr.read_u32::<BigEndian>()),
                secret_key: try!(rdr.read_u32::<BigEndian>())
            },
            b'n' => NoData,
            b'N' => NoticeResponse { fields: try!(read_fields(&mut rdr)) },
            b'R' => try!(read_auth_message(&mut rdr)),
            b's' => PortalSuspended,
            b'S' => ParameterStatus {
                parameter: try!(rdr.read_cstr()),
                value: try!(rdr.read_cstr())
            },
            b't' => try!(read_parameter_description(&mut rdr)),
            b'T' => try!(read_row_description(&mut rdr)),
            b'Z' => ReadyForQuery { _state: try!(rdr.read_u8()) },
            _ => return Err(io::Error::new(io::ErrorKind::Other, "unexpected message tag")),
        };
        if rdr.limit() != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "didn't read entire message"));
        }
        Ok(ret)
    }
}

fn read_fields<R: BufRead>(buf: &mut R) -> io::Result<Vec<(u8, String)>> {
    let mut fields = vec![];
    loop {
        let ty = try!(buf.read_u8());
        if ty == 0 {
            break;
        }

        fields.push((ty, try!(buf.read_cstr())));
    }

    Ok(fields)
}

fn read_data_row<R: BufRead>(buf: &mut R) -> io::Result<BackendMessage> {
    let len = try!(buf.read_u16::<BigEndian>()) as usize;
    let mut values = Vec::with_capacity(len);

    for _ in 0..len {
        let val = match try!(buf.read_i32::<BigEndian>()) {
            -1 => None,
            len => {
                let mut data = vec![0; len as usize];
                try!(util::read_all(buf, &mut data));
                Some(data)
            }
        };
        values.push(val);
    }

    Ok(DataRow { row: values })
}

fn read_auth_message<R: Read>(buf: &mut R) -> io::Result<BackendMessage> {
    Ok(match try!(buf.read_i32::<BigEndian>()) {
        0 => AuthenticationOk,
        2 => AuthenticationKerberosV5,
        3 => AuthenticationCleartextPassword,
        5 => {
            let mut salt = [0; 4];
            try!(util::read_all(buf, &mut salt));
            AuthenticationMD5Password { salt: salt }
        },
        6 => AuthenticationSCMCredential,
        7 => AuthenticationGSS,
        9 => AuthenticationSSPI,
        _ => return Err(io::Error::new(io::ErrorKind::Other, "unexpected authentication tag")),
    })
}

fn read_parameter_description<R: Read>(buf: &mut R) -> io::Result<BackendMessage> {
    let len = try!(buf.read_u16::<BigEndian>()) as usize;
    let mut types = Vec::with_capacity(len);

    for _ in 0..len {
        types.push(try!(buf.read_u32::<BigEndian>()));
    }

    Ok(ParameterDescription { types: types })
}

fn read_row_description<R: BufRead>(buf: &mut R) -> io::Result<BackendMessage> {
    let len = try!(buf.read_u16::<BigEndian>()) as usize;
    let mut types = Vec::with_capacity(len);

    for _ in 0..len {
        types.push(RowDescriptionEntry {
            name: try!(buf.read_cstr()),
            table_oid: try!(buf.read_u32::<BigEndian>()),
            column_id: try!(buf.read_i16::<BigEndian>()),
            type_oid: try!(buf.read_u32::<BigEndian>()),
            type_size: try!(buf.read_i16::<BigEndian>()),
            type_modifier: try!(buf.read_i32::<BigEndian>()),
            format: try!(buf.read_i16::<BigEndian>()),
        })
    }

    Ok(RowDescription { descriptions: types })
}

trait FromUsize {
    fn from_usize(x: usize) -> io::Result<Self>;
}

macro_rules! from_usize {
    ($t:ty) => {
        impl FromUsize for $t {
            fn from_usize(x: usize) -> io::Result<$t> {
                if x > <$t>::max_value() as usize {
                    Err(io::Error::new(io::ErrorKind::InvalidInput, "value too large to transmit"))
                } else {
                    Ok(x as $t)
                }
            }
        }
    }
}

from_usize!(u16);
from_usize!(i32);
from_usize!(u32);
<commit_msg>Remove unneeded impl<commit_after>use std::io;
use std::io::prelude::*;
use std::mem;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use types::Oid;
use util;

use self::BackendMessage::*;
use self::FrontendMessage::*;

pub const PROTOCOL_VERSION: u32 = 0x0003_0000;
pub const CANCEL_CODE: u32 = 80877102;
pub const SSL_CODE: u32 = 80877103;

pub enum BackendMessage {
    AuthenticationCleartextPassword,
    AuthenticationGSS,
    AuthenticationKerberosV5,
    AuthenticationMD5Password {
        salt: [u8; 4]
    },
    AuthenticationOk,
    AuthenticationSCMCredential,
    AuthenticationSSPI,
    BackendKeyData {
        process_id: u32,
        secret_key: u32
    },
    BindComplete,
    CloseComplete,
    CommandComplete {
        tag: String,
    },
    CopyInResponse {
        format: u8,
        column_formats: Vec<u16>,
    },
    DataRow {
        row: Vec<Option<Vec<u8>>>
    },
    EmptyQueryResponse,
    ErrorResponse {
        fields: Vec<(u8, String)>
    },
    NoData,
    NoticeResponse {
        fields: Vec<(u8, String)>
    },
    NotificationResponse {
        pid: u32,
        channel: String,
        payload: String,
    },
    ParameterDescription {
        types: Vec<Oid>
    },
    ParameterStatus {
        parameter: String,
        value: String,
    },
    ParseComplete,
    PortalSuspended,
    ReadyForQuery {
        _state: u8
    },
    RowDescription {
        descriptions: Vec<RowDescriptionEntry>
    }
}

pub struct RowDescriptionEntry {
    pub name: String,
    pub table_oid: Oid,
    pub column_id: i16,
    pub type_oid: Oid,
    pub type_size: i16,
    pub type_modifier: i32,
    pub format: i16
}

pub enum FrontendMessage<'a> {
    Bind {
        portal: &'a str,
        statement: &'a str,
        formats: &'a [i16],
        values: &'a [Option<Vec<u8>>],
        result_formats: &'a [i16]
    },
    CancelRequest {
        code: u32,
        process_id: u32,
        secret_key: u32,
    },
    Close {
        variant: u8,
        name: &'a str
    },
    CopyData {
        data: &'a [u8],
    },
    CopyDone,
    CopyFail {
        message: &'a str
    },
    Describe {
        variant: u8,
        name: &'a str
    },
    Execute {
        portal: &'a str,
        max_rows: i32
    },
    Parse {
        name: &'a str,
        query: &'a str,
        param_types: &'a [Oid]
    },
    PasswordMessage {
        password: &'a str
    },
    Query {
        query: &'a str
    },
    SslRequest {
        code: u32
    },
    StartupMessage {
        version: u32,
        parameters: &'a [(String, String)]
    },
    Sync,
    Terminate
}

#[doc(hidden)]
trait WriteCStr {
    fn write_cstr(&mut self, s: &str) -> io::Result<()>;
}

impl<W: Write> WriteCStr for W {
    fn write_cstr(&mut self, s: &str) -> io::Result<()> {
        try!(self.write_all(s.as_bytes()));
        Ok(try!(self.write_u8(0)))
    }
}

#[doc(hidden)]
pub trait WriteMessage {
    fn write_message(&mut self, &FrontendMessage) -> io::Result<()> ;
}

impl<W: Write> WriteMessage for W {
    fn write_message(&mut self, message: &FrontendMessage) -> io::Result<()> {
        let mut buf = vec![];
        let mut ident = None;

        match *message {
            Bind { portal, statement, formats, values, result_formats } => {
                ident = Some(b'B');
                try!(buf.write_cstr(portal));
                try!(buf.write_cstr(statement));

                try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(formats.len()))));
                for &format in formats {
                    try!(buf.write_i16::<BigEndian>(format));
                }

                try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(values.len()))));
                for value in values {
                    match *value {
                        None => try!(buf.write_i32::<BigEndian>(-1)),
                        Some(ref value) => {
                            try!(buf.write_i32::<BigEndian>(try!(i32::from_usize(value.len()))));
                            try!(buf.write_all(&**value));
                        }
                    }
                }

                try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(result_formats.len()))));
                for &format in result_formats {
                    try!(buf.write_i16::<BigEndian>(format));
                }
            }
            CancelRequest { code, process_id, secret_key } => {
                try!(buf.write_u32::<BigEndian>(code));
                try!(buf.write_u32::<BigEndian>(process_id));
                try!(buf.write_u32::<BigEndian>(secret_key));
            }
            Close { variant, name } => {
                ident = Some(b'C');
                try!(buf.write_u8(variant));
                try!(buf.write_cstr(name));
            }
            CopyData { data } => {
                ident = Some(b'd');
                try!(buf.write_all(data));
            }
            CopyDone => ident = Some(b'c'),
            CopyFail { message } => {
                ident = Some(b'f');
                try!(buf.write_cstr(message));
            }
            Describe { variant, name } => {
                ident = Some(b'D');
                try!(buf.write_u8(variant));
                try!(buf.write_cstr(name));
            }
            Execute { portal, max_rows } => {
                ident = Some(b'E');
                try!(buf.write_cstr(portal));
                try!(buf.write_i32::<BigEndian>(max_rows));
            }
            Parse { name, query, param_types } => {
                ident = Some(b'P');
                try!(buf.write_cstr(name));
                try!(buf.write_cstr(query));
                try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(param_types.len()))));
                for &ty in param_types {
                    try!(buf.write_u32::<BigEndian>(ty));
                }
            }
            PasswordMessage { password } => {
                ident = Some(b'p');
                try!(buf.write_cstr(password));
            }
            Query { query } => {
                ident = Some(b'Q');
                try!(buf.write_cstr(query));
            }
            StartupMessage { version, parameters } => {
                try!(buf.write_u32::<BigEndian>(version));
                for &(ref k, ref v) in parameters {
                    try!(buf.write_cstr(&**k));
                    try!(buf.write_cstr(&**v));
                }
                try!(buf.write_u8(0));
            }
            SslRequest { code } => try!(buf.write_u32::<BigEndian>(code)),
            Sync => ident = Some(b'S'),
            Terminate => ident = Some(b'X'),
        }

        if let Some(ident) = ident {
            try!(self.write_u8(ident));
        }

        // add size of length value
        if buf.len() > u32::max_value() as usize - mem::size_of::<u32>() {
            return Err(io::Error::new(io::ErrorKind::InvalidInput, "value too large to transmit"));
        }
        try!(self.write_u32::<BigEndian>((buf.len() + mem::size_of::<u32>()) as u32));
        try!(self.write_all(&*buf));

        Ok(())
    }
}

#[doc(hidden)]
trait ReadCStr {
    fn read_cstr(&mut self) -> io::Result<String>;
}

impl<R: BufRead> ReadCStr for R {
    fn read_cstr(&mut self) -> io::Result<String> {
        let mut buf = vec![];
        try!(self.read_until(0, &mut buf));
        buf.pop();
        String::from_utf8(buf).map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

#[doc(hidden)]
pub trait ReadMessage {
    fn read_message(&mut self) -> io::Result<BackendMessage>;
}

impl<R: BufRead> ReadMessage for R {
    fn read_message(&mut self) -> io::Result<BackendMessage> {
        let ident = try!(self.read_u8());

        // subtract size of length value
        let len = try!(self.read_u32::<BigEndian>()) - mem::size_of::<u32>() as u32;
        let mut rdr = self.by_ref().take(len as u64);

        let ret = match ident {
            b'1' => ParseComplete,
            b'2' => BindComplete,
            b'3' => CloseComplete,
            b'A' => NotificationResponse {
                pid: try!(rdr.read_u32::<BigEndian>()),
                channel: try!(rdr.read_cstr()),
                payload: try!(rdr.read_cstr())
            },
            b'C' => CommandComplete { tag: try!(rdr.read_cstr()) },
            b'D' => try!(read_data_row(&mut rdr)),
            b'E' => ErrorResponse { fields: try!(read_fields(&mut rdr)) },
            b'G' => {
                let format = try!(rdr.read_u8());
                let mut column_formats = vec![];
                for _ in 0..try!(rdr.read_u16::<BigEndian>()) {
                    column_formats.push(try!(rdr.read_u16::<BigEndian>()));
                }
                CopyInResponse {
                    format: format,
                    column_formats: column_formats,
                }
            }
            b'I' => EmptyQueryResponse,
            b'K' => BackendKeyData {
                process_id: try!(rdr.read_u32::<BigEndian>()),
                secret_key: try!(rdr.read_u32::<BigEndian>())
            },
            b'n' => NoData,
            b'N' => NoticeResponse { fields: try!(read_fields(&mut rdr)) },
            b'R' => try!(read_auth_message(&mut rdr)),
            b's' => PortalSuspended,
            b'S' => ParameterStatus {
                parameter: try!(rdr.read_cstr()),
                value: try!(rdr.read_cstr())
            },
            b't' => try!(read_parameter_description(&mut rdr)),
            b'T' => try!(read_row_description(&mut rdr)),
            b'Z' => ReadyForQuery { _state: try!(rdr.read_u8()) },
            _ => return Err(io::Error::new(io::ErrorKind::Other, "unexpected message tag")),
        };
        if rdr.limit() != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "didn't read entire message"));
        }
        Ok(ret)
    }
}

fn read_fields<R: BufRead>(buf: &mut R) -> io::Result<Vec<(u8, String)>> {
    let mut fields = vec![];
    loop {
        let ty = try!(buf.read_u8());
        if ty == 0 {
            break;
        }

        fields.push((ty, try!(buf.read_cstr())));
    }

    Ok(fields)
}

fn read_data_row<R: BufRead>(buf: &mut R) -> io::Result<BackendMessage> {
    let len = try!(buf.read_u16::<BigEndian>()) as usize;
    let mut values = Vec::with_capacity(len);

    for _ in 0..len {
        let val = match try!(buf.read_i32::<BigEndian>()) {
            -1 => None,
            len => {
                let mut data = vec![0; len as usize];
                try!(util::read_all(buf, &mut data));
                Some(data)
            }
        };
        values.push(val);
    }

    Ok(DataRow { row: values })
}

fn read_auth_message<R: Read>(buf: &mut R) -> io::Result<BackendMessage> {
    Ok(match try!(buf.read_i32::<BigEndian>()) {
        0 => AuthenticationOk,
        2 => AuthenticationKerberosV5,
        3 => AuthenticationCleartextPassword,
        5 => {
            let mut salt = [0; 4];
            try!(util::read_all(buf, &mut salt));
            AuthenticationMD5Password { salt: salt }
        },
        6 => AuthenticationSCMCredential,
        7 => AuthenticationGSS,
        9 => AuthenticationSSPI,
        _ => return Err(io::Error::new(io::ErrorKind::Other, "unexpected authentication tag")),
    })
}

fn read_parameter_description<R: Read>(buf: &mut R) -> io::Result<BackendMessage> {
    let len = try!(buf.read_u16::<BigEndian>()) as usize;
    let mut types = Vec::with_capacity(len);

    for _ in 0..len {
        types.push(try!(buf.read_u32::<BigEndian>()));
    }

    Ok(ParameterDescription { types: types })
}

fn read_row_description<R: BufRead>(buf: &mut R) -> io::Result<BackendMessage> {
    let len = try!(buf.read_u16::<BigEndian>()) as usize;
    let mut types = Vec::with_capacity(len);

    for _ in 0..len {
        types.push(RowDescriptionEntry {
            name: try!(buf.read_cstr()),
            table_oid: try!(buf.read_u32::<BigEndian>()),
            column_id: try!(buf.read_i16::<BigEndian>()),
            type_oid: try!(buf.read_u32::<BigEndian>()),
            type_size: try!(buf.read_i16::<BigEndian>()),
            type_modifier: try!(buf.read_i32::<BigEndian>()),
            format: try!(buf.read_i16::<BigEndian>()),
        })
    }

    Ok(RowDescription { descriptions: types })
}

trait FromUsize {
    fn from_usize(x: usize) -> io::Result<Self>;
}

macro_rules! from_usize {
    ($t:ty) => {
        impl FromUsize for $t {
            fn from_usize(x: usize) -> io::Result<$t> {
                if x > <$t>::max_value() as usize {
                    Err(io::Error::new(io::ErrorKind::InvalidInput, "value too large to transmit"))
                } else {
                    Ok(x as $t)
                }
            }
        }
    }
}

from_usize!(u16);
from_usize!(i32);
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::File;

use error::{
    Error, ImapResult, InternalIoError, MessageDecodeError
};

#[deriving(Show)]
enum Flag {
    Answered,
    Draft,
    Flagged,
    Seen
}

#[deriving(Show)]
pub struct Message {
    uid: u32,
    headers: HashMap<String, String>,
    body: Vec<MIMEPart>,
    flags: Vec<Flag>,
    size: u32,
    raw_contents: String
}

#[deriving(Show)]
pub struct MIMEPart {
    mime_header: String,
    mime_body: String
}

impl Message {
    pub fn parse(path: &Path) -> ImapResult<Message> {
        // Load the file contents.
        let file = match File::open(path) {
            Ok(mut file) => match file.read_to_end() {
                Ok(contents) => contents,
                Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to read mail file."))
            },
            Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to open mail file."))
        };
        let raw_contents = String::from_utf8_lossy(file.as_slice()).to_string();

        let mut path = path.filename_str().unwrap().splitn(1, ':');
        let filename = path.next().unwrap();
        let flags = path.next().unwrap();

        // Retrieve the UID from the provided filename.
        let uid = match from_str::<u32>(filename) {
            Some(uid) => uid,
            None => return Err(Error::simple(MessageDecodeError, "Failed to retrieve UID from filename."))
        };
        // Parse the flags from the filename.
        let unparsed_flags = flags.splitn(1, ',').skip(1).next().unwrap();
        let mut flags: Vec<Flag> = Vec::new();
        for flag in unparsed_flags.chars() {
            let flag = match flag {
                'D' => Some(Draft),
                'F' => Some(Flagged),
                'R' => Some(Answered),
                'S' => Some(Seen),
                _ => None
            };
            match flag {
                Some(flag) => flags.push(flag),
                None => { }
            };
        }

        let header_boundary = raw_contents.as_slice().find_str("\n\n").unwrap();
        let raw_header = raw_contents.as_slice().slice_to(header_boundary);
        let raw_body = raw_contents.as_slice().slice_from(header_boundary + 2);

        // Iterate over the lines of the header in reverse.
        // If a line with leading whitespace is detected, it is merged to the line before it.
        // This "unwraps" the header as indicated in RFC 2822 2.2.3
        let mut parsed_header: Vec<String> = Vec::new();
        let mut iterator = raw_header.lines().rev();
        loop {
            let line = match iterator.next() {
                Some(line) => line,
                None => break
            };
            let mut field = line.to_string();
            if line.as_slice().starts_with(" ") || line.as_slice().starts_with("\t") {
                field = field.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                loop {
                    let next = iterator.next().unwrap().to_string();
                    let mut trimmed_next = next.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                    // Add a space between the merged lines.
                    trimmed_next.push_str(" ".as_slice());
                    trimmed_next.push_str(field.as_slice());
                    field = trimmed_next;
                    if !next.as_slice().starts_with(" ") && !next.as_slice().starts_with("\t") {
                        break;
                    }
                }
            }

            parsed_header.push(field.to_string());
        }
        let parsed_header: Vec<&String> = parsed_header.iter().rev().collect();

        let mut headers = HashMap::new();
        for line in parsed_header.iter() {
            let split: Vec<&str> = line.as_slice().splitn(1, ':').collect();
            headers.insert(split[0].clone().to_string(), split[1].slice_from(1).clone().to_string());
        }
        // Remove the "Received" key from the HashMap.
        headers.remove(&"Received".to_string());

        // Determine whether the message is MULTIPART or not.
        let content_type = headers["Content-Type".to_string()].clone();
        let mut body = Vec::new();
        if content_type.as_slice().contains("MULTIPART") {
            let mime_boundary = {
                let value: Vec<&str> = content_type.as_slice().split_str("BOUNDARY=\"").collect();
                if value.len() < 2 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                let value: Vec<&str> = value[1].splitn(1, '"').collect();
                if value.len() < 1 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                format!("--{}--\n", value[0])
            };

            let first_content_type_index = match raw_body.find_str("Content-Type") {
                Some(val) => val,
                None => return Err(Error::simple(MessageDecodeError, "Missing Content-Type for body part"))
            };
            let raw_body = raw_body.slice_from(first_content_type_index);
            let raw_body: Vec<&str> = raw_body.split_str(mime_boundary.as_slice()).collect();
            let raw_body = raw_body.slice_to(raw_body.len() - 1);

            for part in raw_body.iter() {
                let header_boundary = part.as_slice().find_str("\n\n").unwrap();
                let header = part.as_slice().slice_to(header_boundary);
                let mut content_type = String::new();
                for line in header.lines() {
                    let split_line: Vec<&str> = line.splitn(1, ':').collect();
                    if split_line[0] == "Content-Type" {
                        let content_type_values: Vec<&str> = split_line[1].splitn(1, ';').collect();
                        content_type = content_type_values[0].slice_from(1).to_string();
                        break;
                    }
                }
                let body_part = MIMEPart {
                    mime_header: content_type.to_string(),
                    mime_body: raw_body.to_string()
                };
                body.push(body_part);
            }
        } else {
            let body_part = MIMEPart {
                mime_header: content_type.to_string(),
                mime_body: raw_body.to_string()
            };
            body.push(body_part);
        }

        let message = Message {
            uid: uid,
            headers: headers,
            body: body,
            flags: flags,
            size: 0u32,
            raw_contents: raw_contents.clone()
        };

        Ok(message)
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn date_received(&self) -> &String {
        self.headers.find(&"Received-On-Date".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_from(&self) -> &String {
        self.headers.find(&"From".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_to(&self) -> &String {
        self.headers.find(&"To".to_string()).unwrap()
    }
}
<commit_msg>Remove size field<commit_after>use std::collections::HashMap;
use std::io::File;

use error::{
    Error, ImapResult, InternalIoError, MessageDecodeError
};

#[deriving(Show)]
enum Flag {
    Answered,
    Draft,
    Flagged,
    Seen
}

#[deriving(Show)]
pub struct Message {
    uid: u32,
    headers: HashMap<String, String>,
    body: Vec<MIMEPart>,
    flags: Vec<Flag>,
    raw_contents: String
}

#[deriving(Show)]
pub struct MIMEPart {
    mime_header: String,
    mime_body: String
}

impl Message {
    pub fn parse(path: &Path) -> ImapResult<Message> {
        // Load the file contents.
        let file = match File::open(path) {
            Ok(mut file) => match file.read_to_end() {
                Ok(contents) => contents,
                Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to read mail file."))
            },
            Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to open mail file."))
        };
        let raw_contents = String::from_utf8_lossy(file.as_slice()).to_string();

        let mut path = path.filename_str().unwrap().splitn(1, ':');
        let filename = path.next().unwrap();
        let flags = path.next().unwrap();

        // Retrieve the UID from the provided filename.
        let uid = match from_str::<u32>(filename) {
            Some(uid) => uid,
            None => return Err(Error::simple(MessageDecodeError, "Failed to retrieve UID from filename."))
        };
        // Parse the flags from the filename.
        let unparsed_flags = flags.splitn(1, ',').skip(1).next().unwrap();
        let mut flags: Vec<Flag> = Vec::new();
        for flag in unparsed_flags.chars() {
            let flag = match flag {
                'D' => Some(Draft),
                'F' => Some(Flagged),
                'R' => Some(Answered),
                'S' => Some(Seen),
                _ => None
            };
            match flag {
                Some(flag) => flags.push(flag),
                None => { }
            };
        }

        let header_boundary = raw_contents.as_slice().find_str("\n\n").unwrap();
        let raw_header = raw_contents.as_slice().slice_to(header_boundary);
        let raw_body = raw_contents.as_slice().slice_from(header_boundary + 2);

        // Iterate over the lines of the header in reverse.
        // If a line with leading whitespace is detected, it is merged to the line before it.
        // This "unwraps" the header as indicated in RFC 2822 2.2.3
        let mut parsed_header: Vec<String> = Vec::new();
        let mut iterator = raw_header.lines().rev();
        loop {
            let line = match iterator.next() {
                Some(line) => line,
                None => break
            };
            let mut field = line.to_string();
            if line.as_slice().starts_with(" ") || line.as_slice().starts_with("\t") {
                field = field.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                loop {
                    let next = iterator.next().unwrap().to_string();
                    let mut trimmed_next = next.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                    // Add a space between the merged lines.
                    trimmed_next.push_str(" ".as_slice());
                    trimmed_next.push_str(field.as_slice());
                    field = trimmed_next;
                    if !next.as_slice().starts_with(" ") && !next.as_slice().starts_with("\t") {
                        break;
                    }
                }
            }

            parsed_header.push(field.to_string());
        }
        let parsed_header: Vec<&String> = parsed_header.iter().rev().collect();

        let mut headers = HashMap::new();
        for line in parsed_header.iter() {
            let split: Vec<&str> = line.as_slice().splitn(1, ':').collect();
            headers.insert(split[0].clone().to_string(), split[1].slice_from(1).clone().to_string());
        }
        // Remove the "Received" key from the HashMap.
        headers.remove(&"Received".to_string());

        // Determine whether the message is MULTIPART or not.
        let content_type = headers["Content-Type".to_string()].clone();
        let mut body = Vec::new();
        if content_type.as_slice().contains("MULTIPART") {
            let mime_boundary = {
                let value: Vec<&str> = content_type.as_slice().split_str("BOUNDARY=\"").collect();
                if value.len() < 2 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                let value: Vec<&str> = value[1].splitn(1, '"').collect();
                if value.len() < 1 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                format!("--{}--\n", value[0])
            };

            let first_content_type_index = match raw_body.find_str("Content-Type") {
                Some(val) => val,
                None => return Err(Error::simple(MessageDecodeError, "Missing Content-Type for body part"))
            };
            let raw_body = raw_body.slice_from(first_content_type_index);
            let raw_body: Vec<&str> = raw_body.split_str(mime_boundary.as_slice()).collect();
            let raw_body = raw_body.slice_to(raw_body.len() - 1);

            for part in raw_body.iter() {
                let header_boundary = part.as_slice().find_str("\n\n").unwrap();
                let header = part.as_slice().slice_to(header_boundary);
                let mut content_type = String::new();
                for line in header.lines() {
                    let split_line: Vec<&str> = line.splitn(1, ':').collect();
                    if split_line[0] == "Content-Type" {
                        let content_type_values: Vec<&str> = split_line[1].splitn(1, ';').collect();
                        content_type = content_type_values[0].slice_from(1).to_string();
                        break;
                    }
                }
                let body_part = MIMEPart {
                    mime_header: content_type.to_string(),
                    mime_body: raw_body.to_string()
                };
                body.push(body_part);
            }
        } else {
            let body_part = MIMEPart {
                mime_header: content_type.to_string(),
                mime_body: raw_body.to_string()
            };
            body.push(body_part);
        }

        let message = Message {
            uid: uid,
            headers: headers,
            body: body,
            flags: flags,
            raw_contents: raw_contents.clone()
        };

        Ok(message)
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn date_received(&self) -> &String {
        self.headers.find(&"Received-On-Date".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_from(&self) -> &String {
        self.headers.find(&"From".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_to(&self) -> &String {
        self.headers.find(&"To".to_string()).unwrap()
    }
}
<|endoftext|>