<commit_before>use std::default::Default;
use std::fmt;
use std::path::{PathBuf, Path};

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

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

/// Contains all the information about a package, as loaded from a Cargo.toml.
#[derive(Clone, Debug)]
pub struct Manifest {
    summary: Summary,
    targets: Vec<Target>,
    links: Option<String>,
    warnings: Vec<String>,
    exclude: Vec<String>,
    include: Vec<String>,
    metadata: ManifestMetadata,
    profiles: Profiles,
}

/// 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.
#[derive(PartialEq, Clone, Debug)]
pub struct ManifestMetadata {
    pub authors: Vec<String>,
    pub keywords: Vec<String>,
    pub license: Option<String>,
    pub license_file: 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
}

#[derive(PartialEq,Clone,RustcEncodable)]
pub struct SerializedManifest {
    name: String,
    version: String,
    dependencies: Vec<SerializedDependency>,
    targets: Vec<Target>,
}

impl Encodable for Manifest {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        SerializedManifest {
            name: self.summary.name().to_string(),
            version: self.summary.version().to_string(),
            dependencies: self.summary.dependencies().iter().map(|d| {
                SerializedDependency::from_dependency(d)
            }).collect(),
            targets: self.targets.clone(),
        }.encode(s)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, RustcEncodable, Copy)]
pub enum LibKind {
    Lib,
    Rlib,
    Dylib,
    StaticLib
}

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

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

#[derive(Debug, Clone, Hash, PartialEq, RustcEncodable, Eq)]
pub enum TargetKind {
    Lib(Vec<LibKind>),
    Bin,
    Test,
    Bench,
    Example,
    CustomBuild,
}

#[derive(RustcEncodable, RustcDecodable, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Profile {
    pub opt_level: u32,
    pub lto: bool,
    pub codegen_units: Option<u32>,    // None = use rustc default
    pub rustc_args: Option<Vec<String>>,
    pub rustdoc_args: Option<Vec<String>>,
    pub debuginfo: bool,
    pub debug_assertions: bool,
    pub rpath: bool,
    pub test: bool,
    pub doc: bool,
    pub run_custom_build: bool,
}

#[derive(Default, Clone, Debug)]
pub struct Profiles {
    pub release: Profile,
    pub dev: Profile,
    pub test: Profile,
    pub bench: Profile,
    pub doc: Profile,
    pub custom_build: Profile,
}

/// Information about a binary, a library, an example, etc. that is part of the
/// package.
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Target {
    kind: TargetKind,
    name: String,
    src_path: PathBuf,
    metadata: Option<Metadata>,
    tested: bool,
    benched: bool,
    doc: bool,
    doctest: bool,
    harness: bool, // whether to use the test harness (--test)
    for_host: bool,
}

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

impl Encodable for Target {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let kind = match self.kind {
            TargetKind::Lib(ref kinds) => {
                kinds.iter().map(|k| k.crate_type()).collect()
            }
            TargetKind::Bin => vec!["bin"],
            TargetKind::Example => vec!["example"],
            TargetKind::Test => vec!["test"],
            TargetKind::CustomBuild => vec!["custom-build"],
            TargetKind::Bench => vec!["bench"],
        };

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

impl Manifest {
    pub fn new(summary: Summary, targets: Vec<Target>,
               exclude: Vec<String>,
               include: Vec<String>,
               links: Option<String>,
               metadata: ManifestMetadata,
               profiles: Profiles) -> Manifest {
        Manifest {
            summary: summary,
            targets: targets,
            warnings: Vec::new(),
            exclude: exclude,
            include: include,
            links: links,
            metadata: metadata,
            profiles: profiles,
        }
    }

    pub fn dependencies(&self) -> &[Dependency] { self.summary.dependencies() }
    pub fn exclude(&self) -> &[String] { &self.exclude }
    pub fn include(&self) -> &[String] { &self.include }
    pub fn metadata(&self) -> &ManifestMetadata { &self.metadata }
    pub fn name(&self) -> &str { self.package_id().name() }
    pub fn package_id(&self) -> &PackageId { self.summary.package_id() }
    pub fn summary(&self) -> &Summary { &self.summary }
    pub fn targets(&self) -> &[Target] { &self.targets }
    pub fn version(&self) -> &Version { self.package_id().version() }
    pub fn warnings(&self) -> &[String] { &self.warnings }
    pub fn profiles(&self) -> &Profiles { &self.profiles }
    pub fn links(&self) -> Option<&str> {
        self.links.as_ref().map(|s| &s[..])
    }

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

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

impl Target {
    fn blank() -> Target {
        Target {
            kind: TargetKind::Bin,
            name: String::new(),
            src_path: PathBuf::new(),
            metadata: None,
            doc: false,
            doctest: false,
            harness: true,
            for_host: false,
            tested: true,
            benched: true,
        }
    }

    pub fn lib_target(name: &str, crate_targets: Vec<LibKind>,
                      src_path: &Path,
                      metadata: Metadata) -> Target {
        Target {
            kind: TargetKind::Lib(crate_targets),
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: Some(metadata),
            doctest: true,
            doc: true,
            ..Target::blank()
        }
    }

    pub fn bin_target(name: &str, src_path: &Path,
                      metadata: Option<Metadata>) -> Target {
        Target {
            kind: TargetKind::Bin,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: metadata,
            doc: true,
            ..Target::blank()
        }
    }

    /// Builds a `Target` corresponding to the `build = "build.rs"` entry.
    pub fn custom_build_target(name: &str, src_path: &Path,
                               metadata: Option<Metadata>) -> Target {
        Target {
            kind: TargetKind::CustomBuild,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: metadata,
            for_host: true,
            benched: false,
            tested: false,
            ..Target::blank()
        }
    }

    pub fn example_target(name: &str, src_path: &Path) -> Target {
        Target {
            kind: TargetKind::Example,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            benched: false,
            ..Target::blank()
        }
    }

    pub fn test_target(name: &str, src_path: &Path,
                       metadata: Metadata) -> Target {
        Target {
            kind: TargetKind::Test,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: Some(metadata),
            benched: false,
            ..Target::blank()
        }
    }

    pub fn bench_target(name: &str, src_path: &Path,
                        metadata: Metadata) -> Target {
        Target {
            kind: TargetKind::Bench,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: Some(metadata),
            tested: false,
            ..Target::blank()
        }
    }

    pub fn name(&self) -> &str { &self.name }
    pub fn crate_name(&self) -> String { self.name.replace("-", "_") }
    pub fn src_path(&self) -> &Path { &self.src_path }
    pub fn metadata(&self) -> Option<&Metadata> { self.metadata.as_ref() }
    pub fn kind(&self) -> &TargetKind { &self.kind }
    pub fn tested(&self) -> bool { self.tested }
    pub fn harness(&self) -> bool { self.harness }
    pub fn documented(&self) -> bool { self.doc }
    pub fn for_host(&self) -> bool { self.for_host }
    pub fn benched(&self) -> bool { self.benched }

    pub fn doctested(&self) -> bool {
        self.doctest && match self.kind {
            TargetKind::Lib(ref kinds) => {
                kinds.contains(&LibKind::Rlib) || kinds.contains(&LibKind::Lib)
            }
            _ => false,
        }
    }

    pub fn allows_underscores(&self) -> bool {
        self.is_bin() || self.is_example() || self.is_custom_build()
    }

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

    pub fn linkable(&self) -> bool {
        match self.kind {
            TargetKind::Lib(ref kinds) => {
                kinds.iter().any(|k| {
                    match *k {
                        LibKind::Lib | LibKind::Rlib | LibKind::Dylib => true,
                        LibKind::StaticLib => false,
                    }
                })
            }
            _ => false
        }
    }

    pub fn is_bin(&self) -> bool { self.kind == TargetKind::Bin }
    pub fn is_example(&self) -> bool { self.kind == TargetKind::Example }
    pub fn is_test(&self) -> bool { self.kind == TargetKind::Test }
    pub fn is_bench(&self) -> bool { self.kind == TargetKind::Bench }
    pub fn is_custom_build(&self) -> bool { self.kind == TargetKind::CustomBuild }

    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
    pub fn rustc_crate_types(&self) -> Vec<&'static str> {
        match self.kind {
            TargetKind::Lib(ref kinds) => {
                kinds.iter().map(|kind| kind.crate_type()).collect()
            },
            TargetKind::CustomBuild |
            TargetKind::Bench |
            TargetKind::Test |
            TargetKind::Example |
            TargetKind::Bin => vec!["bin"],
        }
    }

    pub fn can_lto(&self) -> bool {
        match self.kind {
            TargetKind::Lib(ref v) => *v == [LibKind::StaticLib],
            _ => true,
        }
    }

    pub fn set_tested(&mut self, tested: bool) -> &mut Target {
        self.tested = tested;
        self
    }
    pub fn set_benched(&mut self, benched: bool) -> &mut Target {
        self.benched = benched;
        self
    }
    pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
        self.doctest = doctest;
        self
    }
    pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
        self.for_host = for_host;
        self
    }
    pub fn set_harness(&mut self, harness: bool) -> &mut Target {
        self.harness = harness;
        self
    }
    pub fn set_doc(&mut self, doc: bool) -> &mut Target {
        self.doc = doc;
        self
    }
}

impl fmt::Display for Target {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            TargetKind::Lib(..) => write!(f, "Target(lib)"),
            TargetKind::Bin => write!(f, "Target(bin: {})", self.name),
            TargetKind::Test => write!(f, "Target(test: {})", self.name),
            TargetKind::Bench => write!(f, "Target(bench: {})", self.name),
            TargetKind::Example => write!(f, "Target(example: {})", self.name),
            TargetKind::CustomBuild => write!(f, "Target(script)"),
        }
    }
}

impl Profile {
    pub fn default_dev() -> Profile {
        Profile {
            debuginfo: true,
            debug_assertions: true,
            ..Profile::default()
        }
    }

    pub fn default_release() -> Profile {
        Profile {
            opt_level: 3,
            debuginfo: false,
            ..Profile::default()
        }
    }

    pub fn default_test() -> Profile {
        Profile {
            test: true,
            ..Profile::default_dev()
        }
    }

    pub fn default_bench() -> Profile {
        Profile {
            test: true,
            ..Profile::default_release()
        }
    }

    pub fn default_doc() -> Profile {
        Profile {
            doc: true,
            ..Profile::default_dev()
        }
    }

    pub fn default_custom_build() -> Profile {
        Profile {
            run_custom_build: true,
            ..Profile::default_dev()
        }
    }
}

impl Default for Profile {
    fn default() -> Profile {
        Profile {
            opt_level: 0,
            lto: false,
            codegen_units: None,
            rustc_args: None,
            rustdoc_args: None,
            debuginfo: false,
            debug_assertions: false,
            rpath: false,
            test: false,
            doc: false,
            run_custom_build: false,
        }
    }
}

impl fmt::Display for Profile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.test {
            write!(f, "Profile(test)")
        } else if self.doc {
            write!(f, "Profile(doc)")
        } else if self.run_custom_build {
            write!(f, "Profile(run)")
        } else {
            write!(f, "Profile(build)")
        }

    }
}
<commit_msg>make SerializedManifest private<commit_after>use std::default::Default;
use std::fmt;
use std::path::{PathBuf, Path};

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

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

/// Contains all the information about a package, as loaded from a Cargo.toml.
#[derive(Clone, Debug)]
pub struct Manifest {
    summary: Summary,
    targets: Vec<Target>,
    links: Option<String>,
    warnings: Vec<String>,
    exclude: Vec<String>,
    include: Vec<String>,
    metadata: ManifestMetadata,
    profiles: Profiles,
}

/// 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.
#[derive(PartialEq, Clone, Debug)]
pub struct ManifestMetadata {
    pub authors: Vec<String>,
    pub keywords: Vec<String>,
    pub license: Option<String>,
    pub license_file: 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
}

#[derive(RustcEncodable)]
struct SerializedManifest {
    name: String,
    version: String,
    dependencies: Vec<SerializedDependency>,
    targets: Vec<Target>,
}

impl Encodable for Manifest {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        SerializedManifest {
            name: self.summary.name().to_string(),
            version: self.summary.version().to_string(),
            dependencies: self.summary.dependencies().iter().map(|d| {
                SerializedDependency::from_dependency(d)
            }).collect(),
            targets: self.targets.clone(),
        }.encode(s)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, RustcEncodable, Copy)]
pub enum LibKind {
    Lib,
    Rlib,
    Dylib,
    StaticLib
}

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

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

#[derive(Debug, Clone, Hash, PartialEq, RustcEncodable, Eq)]
pub enum TargetKind {
    Lib(Vec<LibKind>),
    Bin,
    Test,
    Bench,
    Example,
    CustomBuild,
}

#[derive(RustcEncodable, RustcDecodable, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Profile {
    pub opt_level: u32,
    pub lto: bool,
    pub codegen_units: Option<u32>,    // None = use rustc default
    pub rustc_args: Option<Vec<String>>,
    pub rustdoc_args: Option<Vec<String>>,
    pub debuginfo: bool,
    pub debug_assertions: bool,
    pub rpath: bool,
    pub test: bool,
    pub doc: bool,
    pub run_custom_build: bool,
}

#[derive(Default, Clone, Debug)]
pub struct Profiles {
    pub release: Profile,
    pub dev: Profile,
    pub test: Profile,
    pub bench: Profile,
    pub doc: Profile,
    pub custom_build: Profile,
}

/// Information about a binary, a library, an example, etc. that is part of the
/// package.
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Target {
    kind: TargetKind,
    name: String,
    src_path: PathBuf,
    metadata: Option<Metadata>,
    tested: bool,
    benched: bool,
    doc: bool,
    doctest: bool,
    harness: bool, // whether to use the test harness (--test)
    for_host: bool,
}

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

impl Encodable for Target {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let kind = match self.kind {
            TargetKind::Lib(ref kinds) => {
                kinds.iter().map(|k| k.crate_type()).collect()
            }
            TargetKind::Bin => vec!["bin"],
            TargetKind::Example => vec!["example"],
            TargetKind::Test => vec!["test"],
            TargetKind::CustomBuild => vec!["custom-build"],
            TargetKind::Bench => vec!["bench"],
        };

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

impl Manifest {
    pub fn new(summary: Summary, targets: Vec<Target>,
               exclude: Vec<String>,
               include: Vec<String>,
               links: Option<String>,
               metadata: ManifestMetadata,
               profiles: Profiles) -> Manifest {
        Manifest {
            summary: summary,
            targets: targets,
            warnings: Vec::new(),
            exclude: exclude,
            include: include,
            links: links,
            metadata: metadata,
            profiles: profiles,
        }
    }

    pub fn dependencies(&self) -> &[Dependency] { self.summary.dependencies() }
    pub fn exclude(&self) -> &[String] { &self.exclude }
    pub fn include(&self) -> &[String] { &self.include }
    pub fn metadata(&self) -> &ManifestMetadata { &self.metadata }
    pub fn name(&self) -> &str { self.package_id().name() }
    pub fn package_id(&self) -> &PackageId { self.summary.package_id() }
    pub fn summary(&self) -> &Summary { &self.summary }
    pub fn targets(&self) -> &[Target] { &self.targets }
    pub fn version(&self) -> &Version { self.package_id().version() }
    pub fn warnings(&self) -> &[String] { &self.warnings }
    pub fn profiles(&self) -> &Profiles { &self.profiles }
    pub fn links(&self) -> Option<&str> {
        self.links.as_ref().map(|s| &s[..])
    }

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

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

impl Target {
    fn blank() -> Target {
        Target {
            kind: TargetKind::Bin,
            name: String::new(),
            src_path: PathBuf::new(),
            metadata: None,
            doc: false,
            doctest: false,
            harness: true,
            for_host: false,
            tested: true,
            benched: true,
        }
    }

    pub fn lib_target(name: &str, crate_targets: Vec<LibKind>,
                      src_path: &Path,
                      metadata: Metadata) -> Target {
        Target {
            kind: TargetKind::Lib(crate_targets),
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: Some(metadata),
            doctest: true,
            doc: true,
            ..Target::blank()
        }
    }

    pub fn bin_target(name: &str, src_path: &Path,
                      metadata: Option<Metadata>) -> Target {
        Target {
            kind: TargetKind::Bin,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: metadata,
            doc: true,
            ..Target::blank()
        }
    }

    /// Builds a `Target` corresponding to the `build = "build.rs"` entry.
    pub fn custom_build_target(name: &str, src_path: &Path,
                               metadata: Option<Metadata>) -> Target {
        Target {
            kind: TargetKind::CustomBuild,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: metadata,
            for_host: true,
            benched: false,
            tested: false,
            ..Target::blank()
        }
    }

    pub fn example_target(name: &str, src_path: &Path) -> Target {
        Target {
            kind: TargetKind::Example,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            benched: false,
            ..Target::blank()
        }
    }

    pub fn test_target(name: &str, src_path: &Path,
                       metadata: Metadata) -> Target {
        Target {
            kind: TargetKind::Test,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: Some(metadata),
            benched: false,
            ..Target::blank()
        }
    }

    pub fn bench_target(name: &str, src_path: &Path,
                        metadata: Metadata) -> Target {
        Target {
            kind: TargetKind::Bench,
            name: name.to_string(),
            src_path: src_path.to_path_buf(),
            metadata: Some(metadata),
            tested: false,
            ..Target::blank()
        }
    }

    pub fn name(&self) -> &str { &self.name }
    pub fn crate_name(&self) -> String { self.name.replace("-", "_") }
    pub fn src_path(&self) -> &Path { &self.src_path }
    pub fn metadata(&self) -> Option<&Metadata> { self.metadata.as_ref() }
    pub fn kind(&self) -> &TargetKind { &self.kind }
    pub fn tested(&self) -> bool { self.tested }
    pub fn harness(&self) -> bool { self.harness }
    pub fn documented(&self) -> bool { self.doc }
    pub fn for_host(&self) -> bool { self.for_host }
    pub fn benched(&self) -> bool { self.benched }

    pub fn doctested(&self) -> bool {
        self.doctest && match self.kind {
            TargetKind::Lib(ref kinds) => {
                kinds.contains(&LibKind::Rlib) || kinds.contains(&LibKind::Lib)
            }
            _ => false,
        }
    }

    pub fn allows_underscores(&self) -> bool {
        self.is_bin() || self.is_example() || self.is_custom_build()
    }

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

    pub fn linkable(&self) -> bool {
        match self.kind {
            TargetKind::Lib(ref kinds) => {
                kinds.iter().any(|k| {
                    match *k {
                        LibKind::Lib | LibKind::Rlib | LibKind::Dylib => true,
                        LibKind::StaticLib => false,
                    }
                })
            }
            _ => false
        }
    }

    pub fn is_bin(&self) -> bool { self.kind == TargetKind::Bin }
    pub fn is_example(&self) -> bool { self.kind == TargetKind::Example }
    pub fn is_test(&self) -> bool { self.kind == TargetKind::Test }
    pub fn is_bench(&self) -> bool { self.kind == TargetKind::Bench }
    pub fn is_custom_build(&self) -> bool { self.kind == TargetKind::CustomBuild }

    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
    pub fn rustc_crate_types(&self) -> Vec<&'static str> {
        match self.kind {
            TargetKind::Lib(ref kinds) => {
                kinds.iter().map(|kind| kind.crate_type()).collect()
            },
            TargetKind::CustomBuild |
            TargetKind::Bench |
            TargetKind::Test |
            TargetKind::Example |
            TargetKind::Bin => vec!["bin"],
        }
    }

    pub fn can_lto(&self) -> bool {
        match self.kind {
            TargetKind::Lib(ref v) => *v == [LibKind::StaticLib],
            _ => true,
        }
    }

    pub fn set_tested(&mut self, tested: bool) -> &mut Target {
        self.tested = tested;
        self
    }
    pub fn set_benched(&mut self, benched: bool) -> &mut Target {
        self.benched = benched;
        self
    }
    pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
        self.doctest = doctest;
        self
    }
    pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
        self.for_host = for_host;
        self
    }
    pub fn set_harness(&mut self, harness: bool) -> &mut Target {
        self.harness = harness;
        self
    }
    pub fn set_doc(&mut self, doc: bool) -> &mut Target {
        self.doc = doc;
        self
    }
}

impl fmt::Display for Target {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            TargetKind::Lib(..) => write!(f, "Target(lib)"),
            TargetKind::Bin => write!(f, "Target(bin: {})", self.name),
            TargetKind::Test => write!(f, "Target(test: {})", self.name),
            TargetKind::Bench => write!(f, "Target(bench: {})", self.name),
            TargetKind::Example => write!(f, "Target(example: {})", self.name),
            TargetKind::CustomBuild => write!(f, "Target(script)"),
        }
    }
}

impl Profile {
    pub fn default_dev() -> Profile {
        Profile {
            debuginfo: true,
            debug_assertions: true,
            ..Profile::default()
        }
    }

    pub fn default_release() -> Profile {
        Profile {
            opt_level: 3,
            debuginfo: false,
            ..Profile::default()
        }
    }

    pub fn default_test() -> Profile {
        Profile {
            test: true,
            ..Profile::default_dev()
        }
    }

    pub fn default_bench() -> Profile {
        Profile {
            test: true,
            ..Profile::default_release()
        }
    }

    pub fn default_doc() -> Profile {
        Profile {
            doc: true,
            ..Profile::default_dev()
        }
    }

    pub fn default_custom_build() -> Profile {
        Profile {
            run_custom_build: true,
            ..Profile::default_dev()
        }
    }
}

impl Default for Profile {
    fn default() -> Profile {
        Profile {
            opt_level: 0,
            lto: false,
            codegen_units: None,
            rustc_args: None,
            rustdoc_args: None,
            debuginfo: false,
            debug_assertions: false,
            rpath: false,
            test: false,
            doc: false,
            run_custom_build: false,
        }
    }
}

impl fmt::Display for Profile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.test {
            write!(f, "Profile(test)")
        } else if self.doc {
            write!(f, "Profile(doc)")
        } else if self.run_custom_build {
            write!(f, "Profile(run)")
        } else {
            write!(f, "Profile(build)")
        }

    }
}
<|endoftext|>


<commit_before>//! Static files support.

// //! TODO: needs to re-implement actual files handling, current impl blocks
use std::io;
use std::io::Read;
use std::fmt::Write;
use std::fs::{File, DirEntry};
use std::path::{Path, PathBuf};
use std::ops::{Deref, DerefMut};

use mime_guess::get_mime_type;
use route::{Handler, FromRequest};
use recognizer::FromParam;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use httpcodes::HTTPOk;

/// A file with an associated name; responds with the Content-Type based on the
/// file extension.
#[derive(Debug)]
pub struct NamedFile(PathBuf, File);

impl NamedFile {
    /// Attempts to open a file in read-only mode.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use actix_web::fs::NamedFile;
    ///
    /// # #[allow(unused_variables)]
    /// let file = NamedFile::open("foo.txt");
    /// ```
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<NamedFile> {
        let file = File::open(path.as_ref())?;
        Ok(NamedFile(path.as_ref().to_path_buf(), file))
    }

    /// Returns reference to the underlying `File` object.
    #[inline]
    pub fn file(&self) -> &File {
        &self.1
    }

    /// Retrieve the path of this file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use std::io;
    /// use actix_web::fs::NamedFile;
    ///
    /// # #[allow(dead_code)]
    /// # fn path() -> io::Result<()> {
    /// let file = NamedFile::open("test.txt")?;
    /// assert_eq!(file.path().as_os_str(), "foo.txt");
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn path(&self) -> &Path {
        self.0.as_path()
    }
}

impl Deref for NamedFile {
    type Target = File;

    fn deref(&self) -> &File {
        &self.1
    }
}

impl DerefMut for NamedFile {
    fn deref_mut(&mut self) -> &mut File {
        &mut self.1
    }
}

impl FromRequest for NamedFile {
    type Item = HttpResponse;
    type Error = io::Error;

    fn from_request(mut self, _: HttpRequest) -> Result<HttpResponse, io::Error> {
        let mut resp = HTTPOk.build();
        if let Some(ext) = self.path().extension() {
            let mime = get_mime_type(&ext.to_string_lossy());
            resp.content_type(format!("{}", mime).as_str());
        }
        let mut data = Vec::new();
        let _ = self.1.read_to_end(&mut data);
        Ok(resp.body(data).unwrap())
    }
}

/// A directory; responds with the generated directory listing.
#[derive(Debug)]
pub struct Directory{
    base: PathBuf,
    path: PathBuf
}

impl Directory {
    pub fn new(base: PathBuf, path: PathBuf) -> Directory {
        Directory {
            base: base,
            path: path
        }
    }

    fn can_list(&self, entry: &io::Result<DirEntry>) -> bool {
        if let Ok(ref entry) = *entry {
            if let Some(name) = entry.file_name().to_str() {
                if name.starts_with('.') {
                    return false
                }
            }
            if let Ok(ref md) = entry.metadata() {
                let ft = md.file_type();
                return ft.is_dir() || ft.is_file() || ft.is_symlink()
            }
        }
        false
    }
}

impl FromRequest for Directory {
    type Item = HttpResponse;
    type Error = io::Error;

    fn from_request(self, req: HttpRequest) -> Result<HttpResponse, io::Error> {
        let index_of = format!("Index of {}", req.path());
        let mut body = String::new();
        let base = Path::new(req.path());

        for entry in self.path.read_dir()? {
            if self.can_list(&entry) {
                let entry = entry.unwrap();
                let p = match entry.path().strip_prefix(&self.base) {
                    Ok(p) => base.join(p),
                    Err(_) => continue
                };
                // show file url as relative to static path
                let file_url = format!("{}", p.to_string_lossy());

                // if file is a directory, add '/' to the end of the name
                if let Ok(metadata) = entry.metadata() {
                    if metadata.is_dir() {
                        let _ = write!(body, "
{}/
",
                                       file_url, entry.file_name().to_string_lossy());
                    } else {
                        let _ = write!(body, "
{}
",
                                       file_url, entry.file_name().to_string_lossy());
                    }
                } else {
                    continue
                }
            }
        }

        let html = format!("\
                            <title>{}</title>\

{}
\

\
                            {}\

\n", index_of, index_of, body);
        Ok(HTTPOk.build()
           .content_type("text/html; charset=utf-8")
           .body(html).unwrap())
    }
}

/// This enum represents all filesystem elements.
pub enum FilesystemElement {
    File(NamedFile),
    Directory(Directory),
}

impl FromRequest for FilesystemElement {
    type Item = HttpResponse;
    type Error = io::Error;

    fn from_request(self, req: HttpRequest) -> Result<HttpResponse, io::Error> {
        match self {
            FilesystemElement::File(file) => file.from_request(req),
            FilesystemElement::Directory(dir) => dir.from_request(req),
        }
    }
}

/// Static files handling
///
/// Can be registered with `Application::route_handler()`.
///
/// ```rust
/// extern crate actix_web;
///
/// fn main() {
///     let app = actix_web::Application::default("/")
///         .route("/static", actix_web::fs::StaticFiles::new(".", true))
///         .finish();
/// }
/// ```
pub struct StaticFiles {
    directory: PathBuf,
    accessible: bool,
    _show_index: bool,
    _chunk_size: usize,
    _follow_symlinks: bool,
}

impl StaticFiles {
    /// Create new `StaticFiles` instance
    ///
    /// `dir` - base directory
    ///
    /// `index` - show index for directory
    pub fn new<D: Into<PathBuf>>(dir: D, index: bool) -> StaticFiles {
        let dir = dir.into();

        let (dir, access) = match dir.canonicalize() {
            Ok(dir) => {
                if dir.is_dir() {
                    (dir, true)
                } else {
                    warn!("Is not directory `{:?}`", dir);
                    (dir, false)
                }
            },
            Err(err) => {
                warn!("Static files directory `{:?}` error: {}", dir, err);
                (dir, false)
            }
        };

        StaticFiles {
            directory: dir,
            accessible: access,
            _show_index: index,
            _chunk_size: 0,
            _follow_symlinks: false,
        }
    }

}

impl<S> Handler<S> for StaticFiles {
    type Result = Result<FilesystemElement, io::Error>;

    fn handle(&self, req: HttpRequest<S>) -> Self::Result {
        if !self.accessible {
            Err(io::Error::new(io::ErrorKind::NotFound, "not found"))
        } else {
            let relpath = PathBuf::from_param(&req.path()[req.prefix_len()..])
                .map_err(|_| io::Error::new(io::ErrorKind::NotFound, "not found"))?;

            // full filepath
            let path = self.directory.join(&relpath).canonicalize()?;

            if path.is_dir() {
                Ok(FilesystemElement::Directory(Directory::new(self.directory.clone(), path)))
            } else {
                Ok(FilesystemElement::File(NamedFile::open(path)?))
            }
        }
    }
}
<commit_msg>check show_index<commit_after>//! Static files support.

// //! TODO: needs to re-implement actual files handling, current impl blocks
use std::io;
use std::io::Read;
use std::fmt::Write;
use std::fs::{File, DirEntry};
use std::path::{Path, PathBuf};
use std::ops::{Deref, DerefMut};

use mime_guess::get_mime_type;
use route::{Handler, FromRequest};
use recognizer::FromParam;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use httpcodes::HTTPOk;

/// A file with an associated name; responds with the Content-Type based on the
/// file extension.
#[derive(Debug)]
pub struct NamedFile(PathBuf, File);

impl NamedFile {
    /// Attempts to open a file in read-only mode.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use actix_web::fs::NamedFile;
    ///
    /// # #[allow(unused_variables)]
    /// let file = NamedFile::open("foo.txt");
    /// ```
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<NamedFile> {
        let file = File::open(path.as_ref())?;
        Ok(NamedFile(path.as_ref().to_path_buf(), file))
    }

    /// Returns reference to the underlying `File` object.
    #[inline]
    pub fn file(&self) -> &File {
        &self.1
    }

    /// Retrieve the path of this file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use std::io;
    /// use actix_web::fs::NamedFile;
    ///
    /// # #[allow(dead_code)]
    /// # fn path() -> io::Result<()> {
    /// let file = NamedFile::open("test.txt")?;
    /// assert_eq!(file.path().as_os_str(), "foo.txt");
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn path(&self) -> &Path {
        self.0.as_path()
    }
}

impl Deref for NamedFile {
    type Target = File;

    fn deref(&self) -> &File {
        &self.1
    }
}

impl DerefMut for NamedFile {
    fn deref_mut(&mut self) -> &mut File {
        &mut self.1
    }
}

impl FromRequest for NamedFile {
    type Item = HttpResponse;
    type Error = io::Error;

    fn from_request(mut self, _: HttpRequest) -> Result<HttpResponse, io::Error> {
        let mut resp = HTTPOk.build();
        if let Some(ext) = self.path().extension() {
            let mime = get_mime_type(&ext.to_string_lossy());
            resp.content_type(format!("{}", mime).as_str());
        }
        let mut data = Vec::new();
        let _ = self.1.read_to_end(&mut data);
        Ok(resp.body(data).unwrap())
    }
}

/// A directory; responds with the generated directory listing.
#[derive(Debug)]
pub struct Directory{
    base: PathBuf,
    path: PathBuf
}

impl Directory {
    pub fn new(base: PathBuf, path: PathBuf) -> Directory {
        Directory {
            base: base,
            path: path
        }
    }

    fn can_list(&self, entry: &io::Result<DirEntry>) -> bool {
        if let Ok(ref entry) = *entry {
            if let Some(name) = entry.file_name().to_str() {
                if name.starts_with('.') {
                    return false
                }
            }
            if let Ok(ref md) = entry.metadata() {
                let ft = md.file_type();
                return ft.is_dir() || ft.is_file() || ft.is_symlink()
            }
        }
        false
    }
}

impl FromRequest for Directory {
    type Item = HttpResponse;
    type Error = io::Error;

    fn from_request(self, req: HttpRequest) -> Result<HttpResponse, io::Error> {
        let index_of = format!("Index of {}", req.path());
        let mut body = String::new();
        let base = Path::new(req.path());

        for entry in self.path.read_dir()? {
            if self.can_list(&entry) {
                let entry = entry.unwrap();
                let p = match entry.path().strip_prefix(&self.base) {
                    Ok(p) => base.join(p),
                    Err(_) => continue
                };
                // show file url as relative to static path
                let file_url = format!("{}", p.to_string_lossy());

                // if file is a directory, add '/' to the end of the name
                if let Ok(metadata) = entry.metadata() {
                    if metadata.is_dir() {
                        let _ = write!(body, "
{}/
",
                                       file_url, entry.file_name().to_string_lossy());
                    } else {
                        let _ = write!(body, "
{}
",
                                       file_url, entry.file_name().to_string_lossy());
                    }
                } else {
                    continue
                }
            }
        }

        let html = format!("\
                            <title>{}</title>\

{}
\

\
                            {}\

\n", index_of, index_of, body);
        Ok(HTTPOk.build()
           .content_type("text/html; charset=utf-8")
           .body(html).unwrap())
    }
}

/// This enum represents all filesystem elements.
pub enum FilesystemElement {
    File(NamedFile),
    Directory(Directory),
}

impl FromRequest for FilesystemElement {
    type Item = HttpResponse;
    type Error = io::Error;

    fn from_request(self, req: HttpRequest) -> Result<HttpResponse, io::Error> {
        match self {
            FilesystemElement::File(file) => file.from_request(req),
            FilesystemElement::Directory(dir) => dir.from_request(req),
        }
    }
}

/// Static files handling
///
/// Can be registered with `Application::route_handler()`.
///
/// ```rust
/// extern crate actix_web;
///
/// fn main() {
///     let app = actix_web::Application::default("/")
///         .route("/static", actix_web::fs::StaticFiles::new(".", true))
///         .finish();
/// }
/// ```
pub struct StaticFiles {
    directory: PathBuf,
    accessible: bool,
    show_index: bool,
    _chunk_size: usize,
    _follow_symlinks: bool,
}

impl StaticFiles {
    /// Create new `StaticFiles` instance
    ///
    /// `dir` - base directory
    ///
    /// `index` - show index for directory
    pub fn new<D: Into<PathBuf>>(dir: D, index: bool) -> StaticFiles {
        let dir = dir.into();

        let (dir, access) = match dir.canonicalize() {
            Ok(dir) => {
                if dir.is_dir() {
                    (dir, true)
                } else {
                    warn!("Is not directory `{:?}`", dir);
                    (dir, false)
                }
            },
            Err(err) => {
                warn!("Static files directory `{:?}` error: {}", dir, err);
                (dir, false)
            }
        };

        StaticFiles {
            directory: dir,
            accessible: access,
            show_index: index,
            _chunk_size: 0,
            _follow_symlinks: false,
        }
    }

}

impl<S> Handler<S> for StaticFiles {
    type Result = Result<FilesystemElement, io::Error>;

    fn handle(&self, req: HttpRequest<S>) -> Self::Result {
        if !self.accessible {
            Err(io::Error::new(io::ErrorKind::NotFound, "not found"))
        } else {
            let relpath = PathBuf::from_param(&req.path()[req.prefix_len()..])
                .map_err(|_| io::Error::new(io::ErrorKind::NotFound, "not found"))?;

            // full filepath
            let path = self.directory.join(&relpath).canonicalize()?;

            if path.is_dir() {
                if self.show_index {
                    Ok(FilesystemElement::Directory(Directory::new(self.directory.clone(), path)))
                } else {
                    Err(io::Error::new(io::ErrorKind::NotFound, "not found"))
                }
            } else {
                Ok(FilesystemElement::File(NamedFile::open(path)?))
            }
        }
    }
}
<|endoftext|>


<commit_before>use data::DataStore;

pub struct Document{
    id: u64,
    version: u64,
    hash: String,
}

pub struct Transaction{
    version: u64,
}

pub struct VersionIndex{
    document_id: u64,
    versions: Vec<Document>,
}

pub struct Icecore<'a>{
    store: Box<DataStore + 'a>,
    transaction_log: Vec<Transaction>,
    document_index: Vec<VersionIndex>,
}

impl<'a> Icecore<'a>{
    pub fn new(data_store: Box<DataStore + 'a>) -> Icecore<'a>{
        Icecore {
            store: data_store,
            transaction_log: Vec::new(),
            document_index: Vec::new(),
        }
    }

    fn get_next_document_id(&self) -> u64 {
        self.document_index.len().to_u64().expect("document id overflow") + 1
    }

    fn get_next_transaction_id(&self) -> u64 {
        self.transaction_log.len().to_u64().expect("transaction id overflow") + 1
    }

    fn get_version_index(&self, id: u64) -> &VersionIndex {
        self.document_index.index(&(id - 1).to_uint().unwrap())
    }

    fn get_version_index_mut(&mut self, id: u64) -> &mut VersionIndex {
        self.document_index.index_mut(&(id - 1).to_uint().unwrap())
    }

    pub fn insert(&mut self, data: String) -> u64 {
        let hash = self.store.write(data);
        let id = self.get_next_document_id();
        let doc = Document {
            id: id,
            version: self.get_next_transaction_id(),
            hash: hash,
        };
        let mut index = VersionIndex {
            document_id: doc.id,
            versions: Vec::new(),
        };
        index.versions.push(doc);
        self.document_index.push(index);

        id
    }

    pub fn get(&self, id: u64, version: Option<u64>) -> String {
        let index = self.get_version_index(id);
        let doc = match version {
            Some(v) => &index.versions[v.to_uint().unwrap() - 1],
            None => index.versions.last().expect("no document versions found"),
        };
        self.store.read(&doc.hash)
    }

    pub fn update(&mut self, id: u64, data: String) -> u64 {
        let hash = self.store.write(data);
        let version = self.get_next_transaction_id();
        let doc = Document {
            id: id,
            version: version,
            hash: hash,
        };
        let mut index = self.get_version_index_mut(id);
        index.versions.push(doc);

        version
    }
}

<commit_msg>Factored out DocumentIndex<commit_after>use data::DataStore;

pub struct Document{
    id: u64,
    version: u64,
    hash: String,
}

pub struct Transaction{
    version: u64,
}

pub struct VersionIndex{
    document_id: u64,
    versions: Vec<Document>,
}

pub struct DocumentIndex {
    documents: Vec<VersionIndex>,
}

impl DocumentIndex {
    fn new() -> DocumentIndex{
        DocumentIndex {
            documents: Vec::new(),
        }
    }

    fn get_version_index(&self, id: u64) -> &VersionIndex {
        self.documents.index(&(id - 1).to_uint().unwrap())
    }

    fn get_version_index_mut(&mut self, id: u64) -> &mut VersionIndex {
        self.documents.index_mut(&(id - 1).to_uint().unwrap())
    }

    fn get_next_id(&self) -> u64 {
        self.documents.len().to_u64().expect("document id overflow") + 1
    }

    fn add(&mut self, doc: Document) {
        let mut index = VersionIndex {
            document_id: doc.id,
            versions: Vec::new(),
        };
        index.versions.push(doc);
        self.documents.push(index);
    }

}

pub struct Icecore<'a>{
    store: Box<DataStore + 'a>,
    transaction_log: Vec<Transaction>,
    document_index: DocumentIndex,
}

impl<'a> Icecore<'a>{
    pub fn new(data_store: Box<DataStore + 'a>) -> Icecore<'a>{
        Icecore {
            store: data_store,
            transaction_log: Vec::new(),
            document_index: DocumentIndex::new(),
        }
    }

    fn get_next_transaction_id(&self) -> u64 {
        self.transaction_log.len().to_u64().expect("transaction id overflow") + 1
    }

    pub fn insert(&mut self, data: String) -> u64 {
        let hash = self.store.write(data);
        let id = self.document_index.get_next_id();
        let doc = Document {
            id: id,
            version: self.get_next_transaction_id(),
            hash: hash,
        };
        self.document_index.add(doc);

        id
    }

    pub fn get(&self, id: u64, version: Option<u64>) -> String {
        let index = self.document_index.get_version_index(id);
        let doc = match version {
            Some(v) => &index.versions[v.to_uint().unwrap() - 1],
            None => index.versions.last().expect("no document versions found"),
        };
        self.store.read(&doc.hash)
    }

    pub fn update(&mut self, id: u64, data: String) -> u64 {
        let hash = self.store.write(data);
        let version = self.get_next_transaction_id();
        let doc = Document {
            id: id,
            version: version,
            hash: hash,
        };
        let mut index = self.document_index.get_version_index_mut(id);
        index.versions.push(doc);

        version
    }
}

<|endoftext|>


<commit_before>use std::fmt;
use std::fs::File;
use std::io::{self, Read, Write};
use std::sync::Mutex;

use futures::{
    future::{self, Either},
    Future,
};

use vm::api::generic::{A, B};
use vm::api::{Getable, OpaqueValue, OwnedFunction, RuntimeResult, TypedBytecode, WithVM, IO};
use vm::internal::ValuePrinter;
use vm::stack::{self, StackFrame};
use vm::thread::{RootedThread, Thread, ThreadInternal};
use vm::types::*;
use vm::{self, ExternModule, Result};

use compiler_pipeline::*;

use super::{Compiler, Error};

fn print(s: &str) -> IO<()> {
    print!("{}", s);
    IO::Value(())
}

fn println(s: &str) -> IO<()> {
    println!("{}", s);
    IO::Value(())
}

fn flush_stdout() -> IO<()> {
    match io::stdout().flush() {
        Ok(_) => IO::Value(()),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn eprint(s: &str) -> IO<()> {
    eprint!("{}", s);
    IO::Value(())
}

fn eprintln(s: &str) -> IO<()> {
    eprintln!("{}", s);
    IO::Value(())
}

#[derive(Userdata)]
#[gluon(crate_name = "::vm")]
struct GluonFile(Mutex<File>);

impl fmt::Debug for GluonFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "File")
    }
}

fn open_file(s: &str) -> IO<GluonFile> {
    match File::open(s) {
        Ok(f) => IO::Value(GluonFile(Mutex::new(f))),
        Err(err) => IO::Exception(format!("{}", err)),
    }
}

fn read_file_to_array(s: &str) -> IO<Vec<u8>> {
    let mut buffer = Vec::new();
    match File::open(s).and_then(|mut file| file.read_to_end(&mut buffer)) {
        Ok(_) => IO::Value(buffer),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn read_file_to_string(s: &str) -> IO<String> {
    let mut buffer = String::new();
    match File::open(s).and_then(|mut file| file.read_to_string(&mut buffer)) {
        Ok(_) => IO::Value(buffer),
        Err(err) => {
            use std::fmt::Write;
            buffer.clear();
            let _ = write!(&mut buffer, "{}", err);
            IO::Exception(buffer)
        }
    }
}

fn read_file(file: &GluonFile, count: usize) -> IO<Option<Vec<u8>>> {
    if count == 0 {
        return IO::Value(Some(Vec::new()));
    }

    let mut file = file.0.lock().unwrap();
    let mut buffer = Vec::with_capacity(count);
    unsafe {
        buffer.set_len(count);
        match file.read(&mut *buffer) {
            Ok(bytes_read) if bytes_read == 0 => IO::Value(None),
            Ok(bytes_read) => IO::Value(Some(buffer[..bytes_read].to_vec())),
            Err(err) => IO::Exception(format!("{}", err)),
        }
    }
}

fn read_file_to_end(file: &GluonFile) -> IO<Vec<u8>> {
    let mut file = file.0.lock().unwrap();
    let mut buf = Vec::new();

    match file.read_to_end(&mut buf) {
        Ok(_) => IO::Value(buf),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn write_slice_file(
    file: &GluonFile,
    buf: &[u8],
    start: usize,
    end: usize,
) -> RuntimeResult<IO<usize>, String> {
    if start > end {
        return RuntimeResult::Panic(format!(
            "slice index starts at {} but ends at {}",
            start, end
        ));
    }

    if end > buf.len() {
        return RuntimeResult::Panic(format!(
            "index {} is out of range for array of length {}",
            end,
            buf.len()
        ));
    }

    let mut file = file.0.lock().unwrap();

    match file.write(&buf[start..end]) {
        Ok(bytes_written) => RuntimeResult::Return(IO::Value(bytes_written)),
        Err(why) => RuntimeResult::Return(IO::Exception(why.to_string())),
    }
}

fn flush_file(file: &GluonFile) -> IO<()> {
    file.0.lock().unwrap().flush().into()
}

fn read_char() -> IO<char> {
    match io::stdin().bytes().next() {
        Some(result) => match result {
            Ok(b) => ::std::char::from_u32(b as u32)
                .map(IO::Value)
                .unwrap_or_else(|| IO::Exception("Not a valid char".into())),
            Err(err) => IO::Exception(format!("{}", err)),
        },
        None => IO::Exception("No read".into()),
    }
}

fn read_line() -> IO<String> {
    let mut buffer = String::new();
    match io::stdin().read_line(&mut buffer) {
        Ok(_) => IO::Value(buffer),
        Err(err) => {
            use std::fmt::Write;
            buffer.clear();
            let _ = write!(&mut buffer, "{}", err);
            IO::Exception(buffer)
        }
    }
}

/// IO a -> (String -> IO a) -> IO a
fn catch<'vm>(
    action: OpaqueValue<&'vm Thread, IO<A>>,
    mut catch: OwnedFunction<fn(String) -> IO<OpaqueValue<RootedThread, A>>>,
) -> impl Future<Item = IO<OpaqueValue<RootedThread, A>>, Error = vm::Error> {
    let vm = action.vm().root_thread();
    let frame_level = vm.context().frame_level();
    let mut action: OwnedFunction<fn(()) -> OpaqueValue<RootedThread, A>> =
        Getable::from_value(&vm, action.get_variant());

    action.call_fast_async(()).then(move |result| match result {
        Ok(value) => Either::A(future::ok(IO::Value(value))),
        Err(err) => {
            {
                let mut context = vm.context();
                {
                    let mut stack = context.stack_frame::<stack::State>();

                    if let Err(err) = ::vm::thread::reset_stack(stack, frame_level) {
                        return Either::A(future::ok(IO::Exception(err.to_string().into())));
                    }
                }

                let mut stack = context.stack_frame::<stack::State>();
                let len = stack.len();
                stack.pop_many(len - 2);
            }
            Either::B(catch.call_fast_async(format!("{}", err)).then(|result| {
                Ok(match result {
                    Ok(value) => value,
                    Err(err) => IO::Exception(format!("{}", err)),
                })
            }))
        }
    })
}

fn clear_frames<T>(mut err: Error, stack: StackFrame) -> IO<T> {
    let new_trace = match ::vm::thread::reset_stack(stack, 1) {
        Ok(x) => x,
        Err(err) => return IO::Exception(err.to_string()),
    };
    match err {
        // Ignore the stacktrace as we take a more specific range of the stack here
        Error::VM(vm::Error::Panic(_, ref mut trace)) => *trace = Some(new_trace),
        _ => (),
    }
    IO::Exception(err.to_string())
}

field_decl! { value, typ }

// Can't create a minimal reproduction for why this reports as being unused...
#[allow(dead_code)]
type RunExpr = record_type! { value => String, typ => String };

fn run_expr(
    WithVM { vm, value: expr }: WithVM<&str>,
) -> impl Future<Item = IO<RunExpr>, Error = vm::Error> {
    let vm = vm.root_thread();

    let vm1 = vm.clone();
    expr.run_expr(&mut Compiler::new().run_io(true), vm1, "<top>", expr, None)
        .then(move |run_result| {
            let mut context = vm.context();
            let stack = context.stack_frame::<stack::State>();
            Ok(match run_result {
                Ok(execute_value) => {
                    let env = vm.global_env().get_env();
                    let typ = execute_value.typ;
                    let debug_level = vm.global_env().get_debug_level();
                    IO::Value(record_no_decl!{
                        value => ValuePrinter::new(&*env, &typ, execute_value.value.get_variant(), &debug_level).width(80).to_string(),
                        typ => typ.to_string()
                    })
                }
                Err(err) => clear_frames(err, stack),
            })
        })
}

fn load_script(
    WithVM { vm, value: name }: WithVM<&str>,
    expr: &str,
) -> impl Future<Item = IO<String>, Error = vm::Error> {
    let vm1 = vm.root_thread();
    let vm = vm.root_thread();
    let name = name.to_string();
    expr.load_script(&mut Compiler::new(), vm1, &name, expr, None)
        .then(move |run_result| {
            let mut context = vm.context();
            let stack = context.stack_frame::<stack::State>();
            let io = match run_result {
                Ok(()) => IO::Value(format!("Loaded {}", name)),
                Err(err) => clear_frames(err, stack),
            };
            Ok(io)
        })
}

mod std {
    pub mod io {
        pub use io as prim;
    }
}

pub fn load(vm: &Thread) -> Result<ExternModule> {
    vm.register_type::<GluonFile>("File", &[])?;

    // flat_map f m : (a -> IO b) -> IO a -> IO b
    //     = f (m ())
    let flat_map = vec![
        // [f, m, ()]       Initial stack
        Call(1),     // [f, m_ret]       Call m ()
        PushInt(0),  // [f, m_ret, ()]   Add a dummy argument ()
        TailCall(2), /* [f_ret]          Call f m_ret () */
    ];

    type FlatMap = fn(fn(A) -> IO<B>, IO<A>) -> IO<B>;
    type Wrap = fn(A) -> IO<A>;

    let wrap = vec![Pop(1)];

    use self::std;

    // IO functions
    ExternModule::new(
        vm,
        record! {
            type File => GluonFile,
            flat_map => TypedBytecode::<FlatMap>::new("std.io.prim.flat_map", 3, flat_map),
            wrap => TypedBytecode::<Wrap>::new("std.io.prim.wrap", 2, wrap),
            open_file => primitive!(1, std::io::prim::open_file),
            read_file_to_string => primitive!(1, std::io::prim::read_file_to_string),
            read_file_to_array => primitive!(1, std::io::prim::read_file_to_array),
            read_file => primitive!(2, std::io::prim::read_file),
            read_file_to_end => primitive!(1, std::io::prim::read_file_to_end),
            write_slice_file => primitive!(4, std::io::prim::write_slice_file),
            flush_file => primitive!(1, std::io::prim::flush_file),
            read_char => primitive!(0, std::io::prim::read_char),
            read_line => primitive!(0, std::io::prim::read_line),
            print => primitive!(1, std::io::prim::print),
            println => primitive!(1, std::io::prim::println),
            flush_stdout => primitive!(0, std::io::prim::flush_stdout),
            eprint => primitive!(1, std::io::prim::eprint),
            eprintln => primitive!(1, std::io::prim::eprintln),
            catch => primitive!(2, async fn std::io::prim::catch),
            run_expr => primitive!(1, async fn std::io::prim::run_expr),
            load_script => primitive!(2, async fn std::io::prim::load_script),
            default_buf_len => 8192,
        },
    )
}
<commit_msg>feat(std): Add std.io.throw<commit_after>use std::fmt;
use std::fs::File;
use std::io::{self, Read, Write};
use std::sync::Mutex;

use futures::{
    future::{self, Either},
    Future,
};

use vm::api::generic::{A, B};
use vm::api::{Getable, OpaqueValue, OwnedFunction, RuntimeResult, TypedBytecode, WithVM, IO};
use vm::internal::ValuePrinter;
use vm::stack::{self, StackFrame};
use vm::thread::{RootedThread, Thread, ThreadInternal};
use vm::types::*;
use vm::{self, ExternModule, Result};

use compiler_pipeline::*;

use super::{Compiler, Error};

fn print(s: &str) -> IO<()> {
    print!("{}", s);
    IO::Value(())
}

fn println(s: &str) -> IO<()> {
    println!("{}", s);
    IO::Value(())
}

fn flush_stdout() -> IO<()> {
    match io::stdout().flush() {
        Ok(_) => IO::Value(()),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn eprint(s: &str) -> IO<()> {
    eprint!("{}", s);
    IO::Value(())
}

fn eprintln(s: &str) -> IO<()> {
    eprintln!("{}", s);
    IO::Value(())
}

#[derive(Userdata)]
#[gluon(crate_name = "::vm")]
struct GluonFile(Mutex<File>);

impl fmt::Debug for GluonFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "File")
    }
}

fn open_file(s: &str) -> IO<GluonFile> {
    match File::open(s) {
        Ok(f) => IO::Value(GluonFile(Mutex::new(f))),
        Err(err) => IO::Exception(format!("{}", err)),
    }
}

fn read_file_to_array(s: &str) -> IO<Vec<u8>> {
    let mut buffer = Vec::new();
    match File::open(s).and_then(|mut file| file.read_to_end(&mut buffer)) {
        Ok(_) => IO::Value(buffer),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn read_file_to_string(s: &str) -> IO<String> {
    let mut buffer = String::new();
    match File::open(s).and_then(|mut file| file.read_to_string(&mut buffer)) {
        Ok(_) => IO::Value(buffer),
        Err(err) => {
            use std::fmt::Write;
            buffer.clear();
            let _ = write!(&mut buffer, "{}", err);
            IO::Exception(buffer)
        }
    }
}

fn read_file(file: &GluonFile, count: usize) -> IO<Option<Vec<u8>>> {
    if count == 0 {
        return IO::Value(Some(Vec::new()));
    }

    let mut file = file.0.lock().unwrap();
    let mut buffer = Vec::with_capacity(count);
    unsafe {
        buffer.set_len(count);
        match file.read(&mut *buffer) {
            Ok(bytes_read) if bytes_read == 0 => IO::Value(None),
            Ok(bytes_read) => IO::Value(Some(buffer[..bytes_read].to_vec())),
            Err(err) => IO::Exception(format!("{}", err)),
        }
    }
}

fn read_file_to_end(file: &GluonFile) -> IO<Vec<u8>> {
    let mut file = file.0.lock().unwrap();
    let mut buf = Vec::new();

    match file.read_to_end(&mut buf) {
        Ok(_) => IO::Value(buf),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn write_slice_file(
    file: &GluonFile,
    buf: &[u8],
    start: usize,
    end: usize,
) -> RuntimeResult<IO<usize>, String> {
    if start > end {
        return RuntimeResult::Panic(format!(
            "slice index starts at {} but ends at {}",
            start, end
        ));
    }

    if end > buf.len() {
        return RuntimeResult::Panic(format!(
            "index {} is out of range for array of length {}",
            end,
            buf.len()
        ));
    }

    let mut file = file.0.lock().unwrap();

    match file.write(&buf[start..end]) {
        Ok(bytes_written) => RuntimeResult::Return(IO::Value(bytes_written)),
        Err(why) => RuntimeResult::Return(IO::Exception(why.to_string())),
    }
}

fn flush_file(file: &GluonFile) -> IO<()> {
    file.0.lock().unwrap().flush().into()
}

fn read_char() -> IO<char> {
    match io::stdin().bytes().next() {
        Some(result) => match result {
            Ok(b) => ::std::char::from_u32(b as u32)
                .map(IO::Value)
                .unwrap_or_else(|| IO::Exception("Not a valid char".into())),
            Err(err) => IO::Exception(format!("{}", err)),
        },
        None => IO::Exception("No read".into()),
    }
}

fn read_line() -> IO<String> {
    let mut buffer = String::new();
    match io::stdin().read_line(&mut buffer) {
        Ok(_) => IO::Value(buffer),
        Err(err) => {
            use std::fmt::Write;
            buffer.clear();
            let _ = write!(&mut buffer, "{}", err);
            IO::Exception(buffer)
        }
    }
}

/// IO a -> (String -> IO a) -> IO a
fn catch<'vm>(
    action: OpaqueValue<&'vm Thread, IO<A>>,
    mut catch: OwnedFunction<fn(String) -> IO<OpaqueValue<RootedThread, A>>>,
) -> impl Future<Item = IO<OpaqueValue<RootedThread, A>>, Error = vm::Error> {
    let vm = action.vm().root_thread();
    let frame_level = vm.context().frame_level();
    let mut action: OwnedFunction<fn(()) -> OpaqueValue<RootedThread, A>> =
        Getable::from_value(&vm, action.get_variant());

    action.call_fast_async(()).then(move |result| match result {
        Ok(value) => Either::A(future::ok(IO::Value(value))),
        Err(err) => {
            {
                let mut context = vm.context();
                {
                    let mut stack = context.stack_frame::<stack::State>();

                    if let Err(err) = ::vm::thread::reset_stack(stack, frame_level) {
                        return Either::A(future::ok(IO::Exception(err.to_string().into())));
                    }
                }

                let mut stack = context.stack_frame::<stack::State>();
                let len = stack.len();
                stack.pop_many(len - 2);
            }
            Either::B(catch.call_fast_async(format!("{}", err)).then(|result| {
                Ok(match result {
                    Ok(value) => value,
                    Err(err) => IO::Exception(format!("{}", err)),
                })
            }))
        }
    })
}

fn throw(msg: String) -> IO<OpaqueValue<RootedThread, A>> {
    IO::Exception(msg)
}

fn clear_frames<T>(mut err: Error, stack: StackFrame) -> IO<T> {
    let new_trace = match ::vm::thread::reset_stack(stack, 1) {
        Ok(x) => x,
        Err(err) => return IO::Exception(err.to_string()),
    };
    match err {
        // Ignore the stacktrace as we take a more specific range of the stack here
        Error::VM(vm::Error::Panic(_, ref mut trace)) => *trace = Some(new_trace),
        _ => (),
    }
    IO::Exception(err.to_string())
}

field_decl! { value, typ }

// Can't create a minimal reproduction for why this reports as being unused...
#[allow(dead_code)]
type RunExpr = record_type! { value => String, typ => String };

fn run_expr(
    WithVM { vm, value: expr }: WithVM<&str>,
) -> impl Future<Item = IO<RunExpr>, Error = vm::Error> {
    let vm = vm.root_thread();

    let vm1 = vm.clone();
    expr.run_expr(&mut Compiler::new().run_io(true), vm1, "<top>", expr, None)
        .then(move |run_result| {
            let mut context = vm.context();
            let stack = context.stack_frame::<stack::State>();
            Ok(match run_result {
                Ok(execute_value) => {
                    let env = vm.global_env().get_env();
                    let typ = execute_value.typ;
                    let debug_level = vm.global_env().get_debug_level();
                    IO::Value(record_no_decl!{
                        value => ValuePrinter::new(&*env, &typ, execute_value.value.get_variant(), &debug_level).width(80).to_string(),
                        typ => typ.to_string()
                    })
                }
                Err(err) => clear_frames(err, stack),
            })
        })
}

fn load_script(
    WithVM { vm, value: name }: WithVM<&str>,
    expr: &str,
) -> impl Future<Item = IO<String>, Error = vm::Error> {
    let vm1 = vm.root_thread();
    let vm = vm.root_thread();
    let name = name.to_string();
    expr.load_script(&mut Compiler::new(), vm1, &name, expr, None)
        .then(move |run_result| {
            let mut context = vm.context();
            let stack = context.stack_frame::<stack::State>();
            let io = match run_result {
                Ok(()) => IO::Value(format!("Loaded {}", name)),
                Err(err) => clear_frames(err, stack),
            };
            Ok(io)
        })
}

mod std {
    pub mod io {
        pub use io as prim;
    }
}

pub fn load(vm: &Thread) -> Result<ExternModule> {
    vm.register_type::<GluonFile>("File", &[])?;

    // flat_map f m : (a -> IO b) -> IO a -> IO b
    //     = f (m ())
    let flat_map = vec![
        // [f, m, ()]       Initial stack
        Call(1),     // [f, m_ret]       Call m ()
        PushInt(0),  // [f, m_ret, ()]   Add a dummy argument ()
        TailCall(2), /* [f_ret]          Call f m_ret () */
    ];

    type FlatMap = fn(fn(A) -> IO<B>, IO<A>) -> IO<B>;
    type Wrap = fn(A) -> IO<A>;

    let wrap = vec![Pop(1)];

    use self::std;

    // IO functions
    ExternModule::new(
        vm,
        record! {
            type File => GluonFile,
            flat_map => TypedBytecode::<FlatMap>::new("std.io.prim.flat_map", 3, flat_map),
            wrap => TypedBytecode::<Wrap>::new("std.io.prim.wrap", 2, wrap),
            open_file => primitive!(1, std::io::prim::open_file),
            read_file_to_string => primitive!(1, std::io::prim::read_file_to_string),
            read_file_to_array => primitive!(1, std::io::prim::read_file_to_array),
            read_file => primitive!(2, std::io::prim::read_file),
            read_file_to_end => primitive!(1, std::io::prim::read_file_to_end),
            write_slice_file => primitive!(4, std::io::prim::write_slice_file),
            flush_file => primitive!(1, std::io::prim::flush_file),
            read_char => primitive!(0, std::io::prim::read_char),
            read_line => primitive!(0, std::io::prim::read_line),
            print => primitive!(1, std::io::prim::print),
            println => primitive!(1, std::io::prim::println),
            flush_stdout => primitive!(0, std::io::prim::flush_stdout),
            eprint => primitive!(1, std::io::prim::eprint),
            eprintln => primitive!(1, std::io::prim::eprintln),
            catch => primitive!(2, async fn std::io::prim::catch),
            throw => primitive!(1, std::io::prim::throw),
            run_expr => primitive!(1, async fn std::io::prim::run_expr),
            load_script => primitive!(2, async fn std::io::prim::load_script),
            default_buf_len => 8192,
        },
    )
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Input / output.

pub trait InputStream {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize>;

    fn read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let n = try!(self.try_read(buf, min_bytes));
        if n < min_bytes {
            Err(::std::io::Error::new(::std::io::ErrorKind::Other, "Premature EOF", None))
        } else {
            Ok(n)
        }
    }

    fn read_exact(&mut self, buf : &mut [u8]) -> ::std::io::Result<()> {
        let min_bytes = buf.len();
        try!(self.read(buf, min_bytes));
        Ok(())
    }
}

impl <R> InputStream for R where R : ::std::io::Read {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let mut pos = 0;
        let buf_len = buf.len();
        while pos < min_bytes {
            let buf1 = &mut buf[pos .. buf_len];
            let n = try!(self.read(buf1));
            pos += n;
            if n == 0 { return Ok(pos); }
        }
        return Ok(pos);
    }
}

pub trait BufferedInputStream : InputStream {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()>;
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)>;
}

pub struct BufferedInputStreamWrapper<R> {
    inner : R,
    buf : Vec<u8>,
    pos : usize,
    cap : usize
}

impl <R> BufferedInputStreamWrapper<R> {
    pub fn new(r : R) -> BufferedInputStreamWrapper<R> {
        let mut result = BufferedInputStreamWrapper {
            inner : r,
            buf : Vec::with_capacity(8192),
            pos : 0,
            cap : 0
        };
        unsafe {
            result.buf.set_len(8192)
        }
        return result;
    }
}

impl<R: InputStream> BufferedInputStream for BufferedInputStreamWrapper<R> {

   fn skip(&mut self, mut bytes : usize) -> ::std::io::Result<()> {
        let available = self.cap - self.pos;
        if bytes <= available {
            self.pos += bytes;
        } else {
            bytes -= available;
            if bytes <= self.buf.len() {
                //# Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), bytes));
                self.pos = bytes;
                self.cap = n;
            } else {
                //# Forward large skip to the underlying stream.
                panic!("TODO")
            }
        }
        Ok(())
    }

    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        if self.cap - self.pos == 0 {
            let n = try!(self.inner.try_read(self.buf.as_mut_slice(), 1));
            self.cap = n;
            self.pos = 0;
        }
        Ok((self.buf.get_unchecked(self.pos) as *const u8,
            self.buf.get_unchecked(self.cap) as *const u8))
    }
}

impl<R: InputStream> InputStream for BufferedInputStreamWrapper<R> {
    fn try_read(&mut self, mut dst: &mut [u8], mut min_bytes : usize) -> ::std::io::Result<usize> {
        if min_bytes <= self.cap - self.pos {
            // Serve from the current buffer.
            let n = ::std::cmp::min(self.cap - self.pos, dst.len());
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.pos + n]);
            self.pos += n;
            return Ok(n);
        } else {
            // Copy current available into destination.
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.cap]);
            let from_first_buffer = self.cap - self.pos;

            let dst = &mut dst[from_first_buffer ..];
            min_bytes -= from_first_buffer;

            if dst.len() <= self.buf.len() {
                // Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), min_bytes));
                let from_second_buffer = ::std::cmp::min(n, dst.len());
                ::std::slice::bytes::copy_memory(dst,
                                                 &self.buf[0 .. from_second_buffer]);
                self.cap = n;
                self.pos = from_second_buffer;
                return Ok(from_first_buffer + from_second_buffer);
            } else {
                // Forward large read to the underlying stream.
                self.pos = 0;
                self.cap = 0;
                return Ok(from_first_buffer + try!(self.inner.try_read(dst, min_bytes)));
            }
        }
    }
}

pub struct ArrayInputStream<'a> {
    array : &'a [u8]
}

impl <'a> ArrayInputStream<'a> {
    pub fn new<'b>(array : &'b [u8]) -> ArrayInputStream<'b> {
        ArrayInputStream { array : array }
    }
}

impl <'a> InputStream for ArrayInputStream<'a> {
    fn try_read(&mut self, dst: &mut [u8], _min_bytes : usize) -> ::std::io::Result<usize> {
        let n = ::std::cmp::min(dst.len(), self.array.len());
        ::std::slice::bytes::copy_memory(dst, &self.array[0 .. n]);
        self.array = &self.array[n ..];
        Ok(n)
    }
}

impl <'a> BufferedInputStream for ArrayInputStream<'a> {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()> {
        assert!(self.array.len() >= bytes,
                "ArrayInputStream ended prematurely.");
        self.array = &self.array[bytes ..];
        Ok(())
    }
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        let len = self.array.len();
        Ok((self.array.as_ptr() as *const u8,
           self.array.get_unchecked(len) as *const u8))
    }
}

pub trait OutputStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()>;
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl <'a, T : OutputStream> OutputStream for &'a mut T {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        (**self).write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        (**self).flush()
    }
}

pub struct WriteOutputStream<W> {
    writer : W,
}

impl <W : ::std::io::Write> WriteOutputStream <W> {
    pub fn new(writer : W) -> WriteOutputStream<W> {
        WriteOutputStream { writer : writer }
    }
}

impl <W : ::std::io::Write> OutputStream for WriteOutputStream<W> {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        self.writer.write_all(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.writer.flush()
    }
}

pub trait BufferedOutputStream : OutputStream {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8);
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()>;
}

pub struct BufferedOutputStreamWrapper<W> {
    inner: W,
    buf: Vec<u8>,
    pos: usize
}

impl <W> BufferedOutputStreamWrapper<W> {
    pub fn new<'b> (w : W) -> BufferedOutputStreamWrapper<W> {
        let mut result = BufferedOutputStreamWrapper {
            inner: w,
            buf : Vec::with_capacity(8192),
            pos : 0
        };
        unsafe {
            result.buf.set_len(8192);
        }
        return result;
    }
}

impl<W: OutputStream> BufferedOutputStream for BufferedOutputStreamWrapper<W> {
    #[inline]
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.buf.len();
        (self.buf.get_unchecked_mut(self.pos) as *mut u8,
         self.buf.get_unchecked_mut(len) as *mut u8)
    }

    #[inline]
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.buf.get_unchecked_mut(self.pos) as *mut u8;
        if easy_case {
            self.pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }

}

impl<W: OutputStream> OutputStream for BufferedOutputStreamWrapper<W> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        let available = self.buf.len() - self.pos;
        let mut size = buf.len();
        if size <= available {
            let dst = &mut self.buf.as_mut_slice()[self.pos ..];
            ::std::slice::bytes::copy_memory(dst, buf);
            self.pos += size;
        } else if size <= self.buf.len() {
            // Too much for this buffer, but not a full buffer's
            // worth, so we'll go ahead and copy.
            {
                let dst = &mut self.buf.as_mut_slice()[self.pos ..];
                ::std::slice::bytes::copy_memory(dst, &buf[0 .. available]);
            }
            try!(self.inner.write(self.buf.as_mut_slice()));

            size -= available;
            let src = &buf[available ..];
            let dst = &mut self.buf.as_mut_slice()[0 ..];
            ::std::slice::bytes::copy_memory(dst, src);
            self.pos = size;
        } else {
            // Writing so much data that we might as well write
            // directly to avoid a copy.
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
            try!(self.inner.write(buf));
        }
        return Ok(());
    }

    fn flush(&mut self) -> ::std::io::Result<()> {
        if self.pos > 0 {
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
        }
        self.inner.flush()
    }
}

pub struct ArrayOutputStream<'a> {
    array : &'a mut [u8],
    fill_pos : usize,
}

impl <'a> ArrayOutputStream<'a> {
    pub fn new<'b>(array : &'b mut [u8]) -> ArrayOutputStream<'b> {
        ArrayOutputStream {
            array : array,
            fill_pos : 0
        }
    }
}

impl <'a> OutputStream for ArrayOutputStream<'a> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        assert!(buf.len() <= self.array.len() - self.fill_pos,
                "ArrayOutputStream's backing array was not large enough for the data written.");
        ::std::slice::bytes::copy_memory(&mut self.array[self.fill_pos ..], buf);
        self.fill_pos += buf.len();
        Ok(())
    }
}

impl <'a> BufferedOutputStream for ArrayOutputStream<'a> {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.array.len();
        (self.array.get_unchecked_mut(self.fill_pos) as *mut u8,
         self.array.get_unchecked_mut(len) as *mut u8)
    }
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.array.get_unchecked_mut(self.fill_pos) as *mut u8;
        if easy_case {
            self.fill_pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }
}
<commit_msg>impl OutputStream for ::std::io::Write<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Input / output.

pub trait InputStream {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize>;

    fn read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let n = try!(self.try_read(buf, min_bytes));
        if n < min_bytes {
            Err(::std::io::Error::new(::std::io::ErrorKind::Other, "Premature EOF", None))
        } else {
            Ok(n)
        }
    }

    fn read_exact(&mut self, buf : &mut [u8]) -> ::std::io::Result<()> {
        let min_bytes = buf.len();
        try!(self.read(buf, min_bytes));
        Ok(())
    }
}

impl <R> InputStream for R where R : ::std::io::Read {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let mut pos = 0;
        let buf_len = buf.len();
        while pos < min_bytes {
            let buf1 = &mut buf[pos .. buf_len];
            let n = try!(self.read(buf1));
            pos += n;
            if n == 0 { return Ok(pos); }
        }
        return Ok(pos);
    }
}

pub trait BufferedInputStream : InputStream {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()>;
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)>;
}

pub struct BufferedInputStreamWrapper<R> {
    inner : R,
    buf : Vec<u8>,
    pos : usize,
    cap : usize
}

impl <R> BufferedInputStreamWrapper<R> {
    pub fn new(r : R) -> BufferedInputStreamWrapper<R> {
        let mut result = BufferedInputStreamWrapper {
            inner : r,
            buf : Vec::with_capacity(8192),
            pos : 0,
            cap : 0
        };
        unsafe {
            result.buf.set_len(8192)
        }
        return result;
    }
}

impl<R: InputStream> BufferedInputStream for BufferedInputStreamWrapper<R> {

   fn skip(&mut self, mut bytes : usize) -> ::std::io::Result<()> {
        let available = self.cap - self.pos;
        if bytes <= available {
            self.pos += bytes;
        } else {
            bytes -= available;
            if bytes <= self.buf.len() {
                //# Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), bytes));
                self.pos = bytes;
                self.cap = n;
            } else {
                //# Forward large skip to the underlying stream.
                panic!("TODO")
            }
        }
        Ok(())
    }

    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        if self.cap - self.pos == 0 {
            let n = try!(self.inner.try_read(self.buf.as_mut_slice(), 1));
            self.cap = n;
            self.pos = 0;
        }
        Ok((self.buf.get_unchecked(self.pos) as *const u8,
            self.buf.get_unchecked(self.cap) as *const u8))
    }
}

impl<R: InputStream> InputStream for BufferedInputStreamWrapper<R> {
    fn try_read(&mut self, mut dst: &mut [u8], mut min_bytes : usize) -> ::std::io::Result<usize> {
        if min_bytes <= self.cap - self.pos {
            // Serve from the current buffer.
            let n = ::std::cmp::min(self.cap - self.pos, dst.len());
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.pos + n]);
            self.pos += n;
            return Ok(n);
        } else {
            // Copy current available into destination.
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.cap]);
            let from_first_buffer = self.cap - self.pos;

            let dst = &mut dst[from_first_buffer ..];
            min_bytes -= from_first_buffer;

            if dst.len() <= self.buf.len() {
                // Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), min_bytes));
                let from_second_buffer = ::std::cmp::min(n, dst.len());
                ::std::slice::bytes::copy_memory(dst,
                                                 &self.buf[0 .. from_second_buffer]);
                self.cap = n;
                self.pos = from_second_buffer;
                return Ok(from_first_buffer + from_second_buffer);
            } else {
                // Forward large read to the underlying stream.
                self.pos = 0;
                self.cap = 0;
                return Ok(from_first_buffer + try!(self.inner.try_read(dst, min_bytes)));
            }
        }
    }
}

pub struct ArrayInputStream<'a> {
    array : &'a [u8]
}

impl <'a> ArrayInputStream<'a> {
    pub fn new<'b>(array : &'b [u8]) -> ArrayInputStream<'b> {
        ArrayInputStream { array : array }
    }
}

impl <'a> InputStream for ArrayInputStream<'a> {
    fn try_read(&mut self, dst: &mut [u8], _min_bytes : usize) -> ::std::io::Result<usize> {
        let n = ::std::cmp::min(dst.len(), self.array.len());
        ::std::slice::bytes::copy_memory(dst, &self.array[0 .. n]);
        self.array = &self.array[n ..];
        Ok(n)
    }
}

impl <'a> BufferedInputStream for ArrayInputStream<'a> {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()> {
        assert!(self.array.len() >= bytes,
                "ArrayInputStream ended prematurely.");
        self.array = &self.array[bytes ..];
        Ok(())
    }
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        let len = self.array.len();
        Ok((self.array.as_ptr() as *const u8,
           self.array.get_unchecked(len) as *const u8))
    }
}

pub trait OutputStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()>;
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl <W> OutputStream for W where W : ::std::io::Write {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        self.write_all(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.flush()
    }
}

pub trait BufferedOutputStream : OutputStream {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8);
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()>;
}

pub struct BufferedOutputStreamWrapper<'a, W:'a> {
    inner: &'a mut W,
    buf: Vec<u8>,
    pos: usize
}

impl <'a, W> BufferedOutputStreamWrapper<'a, W> {
    pub fn new<'b> (w : &'b mut W) -> BufferedOutputStreamWrapper<W> {
        let mut result = BufferedOutputStreamWrapper {
            inner: w,
            buf : Vec::with_capacity(8192),
            pos : 0
        };
        unsafe {
            result.buf.set_len(8192);
        }
        return result;
    }
}

impl<'a, W: OutputStream> BufferedOutputStream for BufferedOutputStreamWrapper<'a, W> {
    #[inline]
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.buf.len();
        (self.buf.get_unchecked_mut(self.pos) as *mut u8,
         self.buf.get_unchecked_mut(len) as *mut u8)
    }

    #[inline]
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.buf.get_unchecked_mut(self.pos) as *mut u8;
        if easy_case {
            self.pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }

}

impl<'a, W: OutputStream> OutputStream for BufferedOutputStreamWrapper<'a, W> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        let available = self.buf.len() - self.pos;
        let mut size = buf.len();
        if size <= available {
            let dst = &mut self.buf.as_mut_slice()[self.pos ..];
            ::std::slice::bytes::copy_memory(dst, buf);
            self.pos += size;
        } else if size <= self.buf.len() {
            // Too much for this buffer, but not a full buffer's
            // worth, so we'll go ahead and copy.
            {
                let dst = &mut self.buf.as_mut_slice()[self.pos ..];
                ::std::slice::bytes::copy_memory(dst, &buf[0 .. available]);
            }
            try!(self.inner.write(self.buf.as_mut_slice()));

            size -= available;
            let src = &buf[available ..];
            let dst = &mut self.buf.as_mut_slice()[0 ..];
            ::std::slice::bytes::copy_memory(dst, src);
            self.pos = size;
        } else {
            // Writing so much data that we might as well write
            // directly to avoid a copy.
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
            try!(self.inner.write(buf));
        }
        return Ok(());
    }

    fn flush(&mut self) -> ::std::io::Result<()> {
        if self.pos > 0 {
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
        }
        self.inner.flush()
    }
}

pub struct ArrayOutputStream<'a> {
    array : &'a mut [u8],
    fill_pos : usize,
}

impl <'a> ArrayOutputStream<'a> {
    pub fn new<'b>(array : &'b mut [u8]) -> ArrayOutputStream<'b> {
        ArrayOutputStream {
            array : array,
            fill_pos : 0
        }
    }
}

impl <'a> OutputStream for ArrayOutputStream<'a> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        assert!(buf.len() <= self.array.len() - self.fill_pos,
                "ArrayOutputStream's backing array was not large enough for the data written.");
        ::std::slice::bytes::copy_memory(&mut self.array[self.fill_pos ..], buf);
        self.fill_pos += buf.len();
        Ok(())
    }
}

impl <'a> BufferedOutputStream for ArrayOutputStream<'a> {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.array.len();
        (self.array.get_unchecked_mut(self.fill_pos) as *mut u8,
         self.array.get_unchecked_mut(len) as *mut u8)
    }
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.array.get_unchecked_mut(self.fill_pos) as *mut u8;
        if easy_case {
            self.fill_pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }
}
<|endoftext|>