<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Passing structs via FFI should work regardless of whether
// they get passed in multiple registers, byval pointers or the stack

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct Rect {
    a: i32,
    b: i32,
    c: i32,
    d: i32
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct BiggerRect {
    s: Rect,
    a: i32,
    b: i32
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct FloatRect {
    a: i32,
    b: i32,
    c: f64
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct Huge {
    a: i32,
    b: i32,
    c: i32,
    d: i32,
    e: i32
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct FloatPoint {
    x: f64,
    y: f64
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct FloatOne {
    x: f64,
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct IntOdd {
    a: i8,
    b: i8,
    c: i8,
}

#[link(name = "test", kind = "static")]
extern {
    fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);

    fn byval_many_rect(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, s: Rect);

    fn byval_rect_floats(a: f32, b: f32, c: f64, d: f32, e: f32,
                         f: f32, g: f64, s: Rect, t: FloatRect);

    fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect);

    fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);

    fn split_rect(a: i32, b: i32, s: Rect);

    fn split_rect_floats(a: f32, b: f32, s: FloatRect);

    fn split_rect_with_floats(a: i32, b: i32, c: f32, d: i32, e: f32, f: i32, s: Rect);

    fn split_and_byval_rect(a: i32, b: i32, c: i32, s: Rect, t: Rect);

    fn split_ret_byval_struct(a: i32, b: i32, s: Rect) -> Rect;

    fn sret_byval_struct(a: i32, b: i32, c: i32, d: i32, s: Rect) -> BiggerRect;

    fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect;

    fn huge_struct(s: Huge) -> Huge;

    fn float_point(p: FloatPoint) -> FloatPoint;

    fn float_one(f: FloatOne) -> FloatOne;

    fn int_odd(i: IntOdd) -> IntOdd;
}

fn main() {
    let s = Rect { a: 553, b: 554, c: 555, d: 556 };
    let t = BiggerRect { s: s, a: 27834, b: 7657 };
    let u = FloatRect { a: 3489, b: 3490, c: 8. };
    let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
    let p = FloatPoint { x: 5., y: -3. };
    let f1 = FloatOne { x: 7. };
    let i = IntOdd { a: 1, b: 2, c: 3 };

    unsafe {
        byval_rect(1, 2, 3, 4, 5, s);
        byval_many_rect(1, 2, 3, 4, 5, 6, s);
        byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u);
        byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s);
        byval_rect_with_many_huge(v, v, v, v, v, v, Rect {
            a: 123,
            b: 456,
            c: 789,
            d: 420
        });
        split_rect(1, 2, s);
        split_rect_floats(1., 2., u);
        split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s);
        split_and_byval_rect(1, 2, 3, s, s);
        split_rect(1, 2, s);
        assert_eq!(huge_struct(v), v);
        assert_eq!(split_ret_byval_struct(1, 2, s), s);
        assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
        assert_eq!(sret_split_struct(1, 2, s), t);
        assert_eq!(float_point(p), p);
        assert_eq!(int_odd(i), i);

        // mingw64-gcc uses the wrong ABI:
        // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
        #[cfg(not(all(windows, target_arch = "x86_64", target_env = "gnu")))]
        assert_eq!(float_one(f1), f1);
    }
}
<commit_msg>Exclude all windows-gnu from the float_one test<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Passing structs via FFI should work regardless of whether
// they get passed in multiple registers, byval pointers or the stack

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct Rect {
    a: i32,
    b: i32,
    c: i32,
    d: i32
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct BiggerRect {
    s: Rect,
    a: i32,
    b: i32
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct FloatRect {
    a: i32,
    b: i32,
    c: f64
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct Huge {
    a: i32,
    b: i32,
    c: i32,
    d: i32,
    e: i32
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct FloatPoint {
    x: f64,
    y: f64
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct FloatOne {
    x: f64,
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct IntOdd {
    a: i8,
    b: i8,
    c: i8,
}

#[link(name = "test", kind = "static")]
extern {
    fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);

    fn byval_many_rect(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, s: Rect);

    fn byval_rect_floats(a: f32, b: f32, c: f64, d: f32, e: f32,
                         f: f32, g: f64, s: Rect, t: FloatRect);

    fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect);

    fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);

    fn split_rect(a: i32, b: i32, s: Rect);

    fn split_rect_floats(a: f32, b: f32, s: FloatRect);

    fn split_rect_with_floats(a: i32, b: i32, c: f32, d: i32, e: f32, f: i32, s: Rect);

    fn split_and_byval_rect(a: i32, b: i32, c: i32, s: Rect, t: Rect);

    fn split_ret_byval_struct(a: i32, b: i32, s: Rect) -> Rect;

    fn sret_byval_struct(a: i32, b: i32, c: i32, d: i32, s: Rect) -> BiggerRect;

    fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect;

    fn huge_struct(s: Huge) -> Huge;

    fn float_point(p: FloatPoint) -> FloatPoint;

    fn float_one(f: FloatOne) -> FloatOne;

    fn int_odd(i: IntOdd) -> IntOdd;
}

fn main() {
    let s = Rect { a: 553, b: 554, c: 555, d: 556 };
    let t = BiggerRect { s: s, a: 27834, b: 7657 };
    let u = FloatRect { a: 3489, b: 3490, c: 8. };
    let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
    let p = FloatPoint { x: 5., y: -3. };
    let f1 = FloatOne { x: 7. };
    let i = IntOdd { a: 1, b: 2, c: 3 };

    unsafe {
        byval_rect(1, 2, 3, 4, 5, s);
        byval_many_rect(1, 2, 3, 4, 5, 6, s);
        byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u);
        byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s);
        byval_rect_with_many_huge(v, v, v, v, v, v, Rect {
            a: 123,
            b: 456,
            c: 789,
            d: 420
        });
        split_rect(1, 2, s);
        split_rect_floats(1., 2., u);
        split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s);
        split_and_byval_rect(1, 2, 3, s, s);
        split_rect(1, 2, s);
        assert_eq!(huge_struct(v), v);
        assert_eq!(split_ret_byval_struct(1, 2, s), s);
        assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
        assert_eq!(sret_split_struct(1, 2, s), t);
        assert_eq!(float_point(p), p);
        assert_eq!(int_odd(i), i);

        // MSVC/GCC/Clang are not consistent in the ABI of single-float aggregates.
        // x86_64: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
        // i686: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82041
        #[cfg(not(all(windows, target_env = "gnu")))]
        assert_eq!(float_one(f1), f1);
    }
}
<|endoftext|>


<commit_before><commit_msg>ICH: Add test case for call expressions.<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This test case tests the incremental compilation hash (ICH) implementation
// for function and method call expressions.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

fn callee1(_x: u32, _y: i64) {}
fn callee2(_x: u32, _y: i64) {}

// Change Callee (Function) ----------------------------------------------------
#[cfg(cfail1)]
pub fn change_callee_function() {
    callee1(1, 2)
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_callee_function() {
    callee2(1, 2)
}

// Change Argument (Function) --------------------------------------------------
#[cfg(cfail1)]
pub fn change_argument_function() {
    callee1(1, 2)
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_argument_function() {
    callee1(1, 3)
}

// Change Callee Indirectly (Function) -----------------------------------------
mod change_callee_indirectly_function {
    #[cfg(cfail1)]
    use super::callee1 as callee;
    #[cfg(not(cfail1))]
    use super::callee2 as callee;

    #[rustc_dirty(label="Hir", cfg="cfail2")]
    #[rustc_clean(label="Hir", cfg="cfail3")]
    #[rustc_metadata_dirty(cfg="cfail2")]
    #[rustc_metadata_clean(cfg="cfail3")]
    pub fn change_callee_indirectly_function() {
        callee(1, 2)
    }
}

struct Struct;
impl Struct {
    fn method1(&self, _x: char, _y: bool) {}
    fn method2(&self, _x: char, _y: bool) {}
}

// Change Callee (Method) ------------------------------------------------------
#[cfg(cfail1)]
pub fn change_callee_method() {
    let s = Struct;
    s.method1('x', true);
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_callee_method() {
    let s = Struct;
    s.method2('x', true);
}

// Change Argument (Method) ----------------------------------------------------
#[cfg(cfail1)]
pub fn change_argument_method() {
    let s = Struct;
    s.method1('x', true);
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_argument_method() {
    let s = Struct;
    s.method1('y', true);
}

// Change Callee (Method, UFCS) ------------------------------------------------
#[cfg(cfail1)]
pub fn change_ufcs_callee_method() {
    let s = Struct;
    Struct::method1(&s, 'x', true);
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_ufcs_callee_method() {
    let s = Struct;
    Struct::method2(&s, 'x', true);
}

// Change Argument (Method, UFCS) ----------------------------------------------
#[cfg(cfail1)]
pub fn change_argument_method_ufcs() {
    let s = Struct;
    Struct::method1(&s, 'x', true);
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_argument_method_ufcs() {
    let s = Struct;
    Struct::method1(&s, 'x', false);
}

// Change To UFCS --------------------------------------------------------------
#[cfg(cfail1)]
pub fn change_to_ufcs() {
    let s = Struct;
    s.method1('x', true);
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_to_ufcs() {
    let s = Struct;
    Struct::method1(&s, 'x', true);
}

struct Struct2;
impl Struct2 {
    fn method1(&self, _x: char, _y: bool) {}
}

// Change UFCS Callee Indirectly -----------------------------------------------
mod change_ufcs_callee_indirectly {
    #[cfg(cfail1)]
    use super::Struct as Struct;
    #[cfg(not(cfail1))]
    use super::Struct2 as Struct;

    #[rustc_dirty(label="Hir", cfg="cfail2")]
    #[rustc_clean(label="Hir", cfg="cfail3")]
    #[rustc_metadata_dirty(cfg="cfail2")]
    #[rustc_metadata_clean(cfg="cfail3")]
    pub fn change_ufcs_callee_indirectly() {
        let s = Struct;
        Struct::method1(&s, 'q', false)
    }
}
<|endoftext|>


<commit_before><commit_msg>Rustfmt.<commit_after><|endoftext|>


<commit_before>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![feature(box_syntax)]

use std::any::Any;
use std::io::prelude::*;
use std::io::{self, Cursor};
use std::fs::File;
use std::path::Path;
use std::sync::mpsc;

use owning_ref::{ErasedBoxRef, OwningRef};
use ar::{Archive, Builder, Header};
use flate2::Compression;
use flate2::write::DeflateEncoder;

use syntax::symbol::Symbol;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::session::Session;
use rustc::session::config::{CrateType, OutputFilenames};
use rustc::ty::TyCtxt;
use rustc::ty::maps::Providers;
use rustc::middle::cstore::EncodedMetadata;
use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait;
use rustc::dep_graph::{DepGraph, DepNode, DepKind};
use rustc_back::target::Target;
use link::{build_link_meta, out_filename};

pub trait TransCrate {
    type MetadataLoader: MetadataLoaderTrait;
    type OngoingCrateTranslation;
    type TranslatedCrate;

    fn metadata_loader() -> Box<MetadataLoaderTrait>;
    fn provide_local(_providers: &mut Providers);
    fn provide_extern(_providers: &mut Providers);
    fn trans_crate<'a, 'tcx>(
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        rx: mpsc::Receiver<Box<Any + Send>>
    ) -> Self::OngoingCrateTranslation;
    fn join_trans(
        trans: Self::OngoingCrateTranslation,
        sess: &Session,
        dep_graph: &DepGraph
    ) -> Self::TranslatedCrate;
    fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames);
    fn dump_incremental_data(trans: &Self::TranslatedCrate);
}

pub struct DummyTransCrate;

impl TransCrate for DummyTransCrate {
    type MetadataLoader = DummyMetadataLoader;
    type OngoingCrateTranslation = ();
    type TranslatedCrate = ();

    fn metadata_loader() -> Box<MetadataLoaderTrait> {
        box DummyMetadataLoader(())
    }

    fn provide_local(_providers: &mut Providers) {
        bug!("DummyTransCrate::provide_local");
    }

    fn provide_extern(_providers: &mut Providers) {
        bug!("DummyTransCrate::provide_extern");
    }

    fn trans_crate<'a, 'tcx>(
        _tcx: TyCtxt<'a, 'tcx, 'tcx>,
        _rx: mpsc::Receiver<Box<Any + Send>>
    ) -> Self::OngoingCrateTranslation {
        bug!("DummyTransCrate::trans_crate");
    }

    fn join_trans(
        _trans: Self::OngoingCrateTranslation,
        _sess: &Session,
        _dep_graph: &DepGraph
    ) -> Self::TranslatedCrate {
        bug!("DummyTransCrate::join_trans");
    }

    fn link_binary(_sess: &Session, _trans: &Self::TranslatedCrate, _outputs: &OutputFilenames) {
        bug!("DummyTransCrate::link_binary");
    }

    fn dump_incremental_data(_trans: &Self::TranslatedCrate) {
        bug!("DummyTransCrate::dump_incremental_data");
    }
}

pub struct DummyMetadataLoader(());

impl MetadataLoaderTrait for DummyMetadataLoader {
    fn get_rlib_metadata(
        &self,
        _target: &Target,
        _filename: &Path
    ) -> Result<ErasedBoxRef<[u8]>, String> {
        bug!("DummyMetadataLoader::get_rlib_metadata");
    }

    fn get_dylib_metadata(
        &self,
        _target: &Target,
        _filename: &Path
    ) -> Result<ErasedBoxRef<[u8]>, String> {
        bug!("DummyMetadataLoader::get_dylib_metadata");
    }
}

pub struct NoLlvmMetadataLoader;

impl MetadataLoaderTrait for NoLlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<ErasedBoxRef<[u8]>, String> {
        let file = File::open(filename)
            .map_err(|e| format!("metadata file open err: {:?}", e))?;
        let mut archive = Archive::new(file);

        while let Some(entry_result) = archive.next_entry() {
            let mut entry = entry_result
                .map_err(|e| format!("metadata section read err: {:?}", e))?;
            if entry.header().identifier() == "rust.metadata.bin" {
                let mut buf = Vec::new();
                io::copy(&mut entry, &mut buf).unwrap();
                let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into();
                return Ok(buf.map_owner_box().erase_owner());
            }
        }

        Err("Couldnt find metadata section".to_string())
    }

    fn get_dylib_metadata(
        &self,
        _target: &Target,
        _filename: &Path,
    ) -> Result<ErasedBoxRef<[u8]>, String> {
        // FIXME: Support reading dylibs from llvm enabled rustc
        self.get_rlib_metadata(_target, _filename)
    }
}

pub struct MetadataOnlyTransCrate;
pub struct OngoingCrateTranslation {
    metadata: EncodedMetadata,
    metadata_version: Vec<u8>,
    crate_name: Symbol,
}
pub struct TranslatedCrate(OngoingCrateTranslation);

impl MetadataOnlyTransCrate {
    #[allow(dead_code)]
    pub fn new() -> Self {
        MetadataOnlyTransCrate
    }
}

impl TransCrate for MetadataOnlyTransCrate {
    type MetadataLoader = NoLlvmMetadataLoader;
    type OngoingCrateTranslation = OngoingCrateTranslation;
    type TranslatedCrate = TranslatedCrate;

    fn metadata_loader() -> Box<MetadataLoaderTrait> {
        box NoLlvmMetadataLoader
    }

    fn provide_local(_providers: &mut Providers) {}
    fn provide_extern(_providers: &mut Providers) {}

    fn trans_crate<'a, 'tcx>(
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        _rx: mpsc::Receiver<Box<Any + Send>>
    ) -> Self::OngoingCrateTranslation {
        ::check_for_rustc_errors_attr(tcx);
        let _ = tcx.link_args(LOCAL_CRATE);
        let _ = tcx.native_libraries(LOCAL_CRATE);
        tcx.sess.abort_if_errors();

        let crate_hash = tcx.dep_graph
                        .fingerprint_of(&DepNode::new_no_params(DepKind::Krate))
                        .unwrap();
        let link_meta = build_link_meta(crate_hash);
        let exported_symbols = ::find_exported_symbols(tcx);
        let (metadata, _hashes) = tcx.encode_metadata(&link_meta, &exported_symbols);

        OngoingCrateTranslation {
            metadata: metadata,
            metadata_version: tcx.metadata_encoding_version().to_vec(),
            crate_name: tcx.crate_name(LOCAL_CRATE),
        }
    }

    fn join_trans(
        trans: Self::OngoingCrateTranslation,
        _sess: &Session,
        _dep_graph: &DepGraph,
    ) -> Self::TranslatedCrate {
        TranslatedCrate(trans)
    }

    fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames) {
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib {
                continue;
            }
            let output_name =
                out_filename(sess, crate_type, &outputs, &trans.0.crate_name.as_str());
            let mut compressed = trans.0.metadata_version.clone();
            let metadata = if crate_type == CrateType::CrateTypeDylib {
                DeflateEncoder::new(&mut compressed, Compression::Fast)
                    .write_all(&trans.0.metadata.raw_data)
                    .unwrap();
                &compressed
            } else {
                &trans.0.metadata.raw_data
            };
            let mut builder = Builder::new(File::create(&output_name).unwrap());
            let header = Header::new("rust.metadata.bin".to_string(), metadata.len() as u64);
            builder.append(&header, Cursor::new(metadata)).unwrap();
        }

        if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib)
            && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib) {
            sess.fatal("Executables are not supported by the metadata-only backend.");
        }
    }

    fn dump_incremental_data(_trans: &Self::TranslatedCrate) {}
}
<commit_msg>Fix error<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![feature(box_syntax)]

use std::any::Any;
use std::io::prelude::*;
use std::io::{self, Cursor};
use std::fs::File;
use std::path::Path;
use std::sync::mpsc;

use owning_ref::{ErasedBoxRef, OwningRef};
use ar::{Archive, Builder, Header};
use flate2::Compression;
use flate2::write::DeflateEncoder;

use syntax::symbol::Symbol;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::session::Session;
use rustc::session::config::{CrateType, OutputFilenames};
use rustc::ty::TyCtxt;
use rustc::ty::maps::Providers;
use rustc::middle::cstore::EncodedMetadata;
use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait;
use rustc::dep_graph::{DepGraph, DepNode, DepKind};
use rustc_back::target::Target;
use link::{build_link_meta, out_filename};

pub trait TransCrate {
    type MetadataLoader: MetadataLoaderTrait;
    type OngoingCrateTranslation;
    type TranslatedCrate;

    fn metadata_loader() -> Box<MetadataLoaderTrait>;
    fn provide_local(_providers: &mut Providers);
    fn provide_extern(_providers: &mut Providers);
    fn trans_crate<'a, 'tcx>(
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        rx: mpsc::Receiver<Box<Any + Send>>
    ) -> Self::OngoingCrateTranslation;
    fn join_trans(
        trans: Self::OngoingCrateTranslation,
        sess: &Session,
        dep_graph: &DepGraph
    ) -> Self::TranslatedCrate;
    fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames);
    fn dump_incremental_data(trans: &Self::TranslatedCrate);
}

pub struct DummyTransCrate;

impl TransCrate for DummyTransCrate {
    type MetadataLoader = DummyMetadataLoader;
    type OngoingCrateTranslation = ();
    type TranslatedCrate = ();

    fn metadata_loader() -> Box<MetadataLoaderTrait> {
        box DummyMetadataLoader(())
    }

    fn provide_local(_providers: &mut Providers) {
        bug!("DummyTransCrate::provide_local");
    }

    fn provide_extern(_providers: &mut Providers) {
        bug!("DummyTransCrate::provide_extern");
    }

    fn trans_crate<'a, 'tcx>(
        _tcx: TyCtxt<'a, 'tcx, 'tcx>,
        _rx: mpsc::Receiver<Box<Any + Send>>
    ) -> Self::OngoingCrateTranslation {
        bug!("DummyTransCrate::trans_crate");
    }

    fn join_trans(
        _trans: Self::OngoingCrateTranslation,
        _sess: &Session,
        _dep_graph: &DepGraph
    ) -> Self::TranslatedCrate {
        bug!("DummyTransCrate::join_trans");
    }

    fn link_binary(_sess: &Session, _trans: &Self::TranslatedCrate, _outputs: &OutputFilenames) {
        bug!("DummyTransCrate::link_binary");
    }

    fn dump_incremental_data(_trans: &Self::TranslatedCrate) {
        bug!("DummyTransCrate::dump_incremental_data");
    }
}

pub struct DummyMetadataLoader(());

impl MetadataLoaderTrait for DummyMetadataLoader {
    fn get_rlib_metadata(
        &self,
        _target: &Target,
        _filename: &Path
    ) -> Result<ErasedBoxRef<[u8]>, String> {
        bug!("DummyMetadataLoader::get_rlib_metadata");
    }

    fn get_dylib_metadata(
        &self,
        _target: &Target,
        _filename: &Path
    ) -> Result<ErasedBoxRef<[u8]>, String> {
        bug!("DummyMetadataLoader::get_dylib_metadata");
    }
}

pub struct NoLlvmMetadataLoader;

impl MetadataLoaderTrait for NoLlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<ErasedBoxRef<[u8]>, String> {
        let file = File::open(filename)
            .map_err(|e| format!("metadata file open err: {:?}", e))?;
        let mut archive = Archive::new(file);

        while let Some(entry_result) = archive.next_entry() {
            let mut entry = entry_result
                .map_err(|e| format!("metadata section read err: {:?}", e))?;
            if entry.header().identifier() == "rust.metadata.bin" {
                let mut buf = Vec::new();
                io::copy(&mut entry, &mut buf).unwrap();
                let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into();
                return Ok(buf.map_owner_box().erase_owner());
            }
        }

        Err("Couldnt find metadata section".to_string())
    }

    fn get_dylib_metadata(
        &self,
        _target: &Target,
        _filename: &Path,
    ) -> Result<ErasedBoxRef<[u8]>, String> {
        // FIXME: Support reading dylibs from llvm enabled rustc
        self.get_rlib_metadata(_target, _filename)
    }
}

pub struct MetadataOnlyTransCrate;
pub struct OngoingCrateTranslation {
    metadata: EncodedMetadata,
    metadata_version: Vec<u8>,
    crate_name: Symbol,
}
pub struct TranslatedCrate(OngoingCrateTranslation);

impl MetadataOnlyTransCrate {
    #[allow(dead_code)]
    pub fn new() -> Self {
        MetadataOnlyTransCrate
    }
}

impl TransCrate for MetadataOnlyTransCrate {
    type MetadataLoader = NoLlvmMetadataLoader;
    type OngoingCrateTranslation = OngoingCrateTranslation;
    type TranslatedCrate = TranslatedCrate;

    fn metadata_loader() -> Box<MetadataLoaderTrait> {
        box NoLlvmMetadataLoader
    }

    fn provide_local(_providers: &mut Providers) {}
    fn provide_extern(_providers: &mut Providers) {}

    fn trans_crate<'a, 'tcx>(
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        _rx: mpsc::Receiver<Box<Any + Send>>
    ) -> Self::OngoingCrateTranslation {
        ::check_for_rustc_errors_attr(tcx);
        let _ = tcx.link_args(LOCAL_CRATE);
        let _ = tcx.native_libraries(LOCAL_CRATE);
        tcx.sess.abort_if_errors();

        let crate_hash = tcx.dep_graph
                        .fingerprint_of(&DepNode::new_no_params(DepKind::Krate));
        let link_meta = build_link_meta(crate_hash);
        let exported_symbols = ::find_exported_symbols(tcx);
        let (metadata, _hashes) = tcx.encode_metadata(&link_meta, &exported_symbols);

        OngoingCrateTranslation {
            metadata: metadata,
            metadata_version: tcx.metadata_encoding_version().to_vec(),
            crate_name: tcx.crate_name(LOCAL_CRATE),
        }
    }

    fn join_trans(
        trans: Self::OngoingCrateTranslation,
        _sess: &Session,
        _dep_graph: &DepGraph,
    ) -> Self::TranslatedCrate {
        TranslatedCrate(trans)
    }

    fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames) {
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib {
                continue;
            }
            let output_name =
                out_filename(sess, crate_type, &outputs, &trans.0.crate_name.as_str());
            let mut compressed = trans.0.metadata_version.clone();
            let metadata = if crate_type == CrateType::CrateTypeDylib {
                DeflateEncoder::new(&mut compressed, Compression::Fast)
                    .write_all(&trans.0.metadata.raw_data)
                    .unwrap();
                &compressed
            } else {
                &trans.0.metadata.raw_data
            };
            let mut builder = Builder::new(File::create(&output_name).unwrap());
            let header = Header::new("rust.metadata.bin".to_string(), metadata.len() as u64);
            builder.append(&header, Cursor::new(metadata)).unwrap();
        }

        if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib)
            && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib) {
            sess.fatal("Executables are not supported by the metadata-only backend.");
        }
    }

    fn dump_incremental_data(_trans: &Self::TranslatedCrate) {}
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Method lookup: the secret sauce of Rust. See `README.md`.

use check::FnCtxt;
use hir::def::Def;
use hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::traits;
use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
use rustc::ty::subst::Subst;
use rustc::infer::{self, InferOk};

use syntax::ast;
use syntax_pos::Span;

use rustc::hir;

pub use self::MethodError::*;
pub use self::CandidateSource::*;

pub use self::suggest::AllTraitsVec;

mod confirm;
pub mod probe;
mod suggest;

use self::probe::{IsSuggestion, ProbeScope};

#[derive(Clone, Copy, Debug)]
pub struct MethodCallee<'tcx> {
    /// Impl method ID, for inherent methods, or trait method ID, otherwise.
    pub def_id: DefId,
    pub substs: &'tcx Substs<'tcx>,

    /// Instantiated method signature, i.e. it has been
    /// substituted, normalized, and has had late-bound
    /// lifetimes replaced with inference variables.
    pub sig: ty::FnSig<'tcx>,
}

pub enum MethodError<'tcx> {
    // Did not find an applicable method, but we did find various near-misses that may work.
    NoMatch(NoMatchData<'tcx>),

    // Multiple methods might apply.
    Ambiguity(Vec<CandidateSource>),

    // Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind.
    ClosureAmbiguity(// DefId of fn trait
                     DefId),

    // Found an applicable method, but it is not visible.
    PrivateMatch(Def),
}

// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
pub struct NoMatchData<'tcx> {
    pub static_candidates: Vec<CandidateSource>,
    pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
    pub out_of_scope_traits: Vec<DefId>,
    pub mode: probe::Mode,
}

impl<'tcx> NoMatchData<'tcx> {
    pub fn new(static_candidates: Vec<CandidateSource>,
               unsatisfied_predicates: Vec<TraitRef<'tcx>>,
               out_of_scope_traits: Vec<DefId>,
               mode: probe::Mode)
               -> Self {
        NoMatchData {
            static_candidates: static_candidates,
            unsatisfied_predicates: unsatisfied_predicates,
            out_of_scope_traits: out_of_scope_traits,
            mode: mode,
        }
    }
}

// A pared down enum describing just the places from which a method
// candidate can arise. Used for error reporting only.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum CandidateSource {
    ImplSource(DefId),
    TraitSource(// trait id
                DefId),
}

impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
    /// Determines whether the type `self_ty` supports a method name `method_name` or not.
    pub fn method_exists(&self,
                         span: Span,
                         method_name: ast::Name,
                         self_ty: ty::Ty<'tcx>,
                         call_expr_id: ast::NodeId,
                         allow_private: bool)
                         -> bool {
        let mode = probe::Mode::MethodCall;
        match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
                                  self_ty, call_expr_id, ProbeScope::TraitsInScope) {
            Ok(..) => true,
            Err(NoMatch(..)) => false,
            Err(Ambiguity(..)) => true,
            Err(ClosureAmbiguity(..)) => true,
            Err(PrivateMatch(..)) => allow_private,
        }
    }

    /// Performs method lookup. If lookup is successful, it will return the callee
    /// and store an appropriate adjustment for the self-expr. In some cases it may
    /// report an error (e.g., invoking the `drop` method).
    ///
    /// # Arguments
    ///
    /// Given a method call like `foo.bar::<T1,...Tn>(...)`:
    ///
    /// * `fcx`:                   the surrounding `FnCtxt` (!)
    /// * `span`:                  the span for the method call
    /// * `method_name`:           the name of the method being called (`bar`)
    /// * `self_ty`:               the (unadjusted) type of the self expression (`foo`)
    /// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`)
    /// * `self_expr`:             the self expression (`foo`)
    pub fn lookup_method(&self,
                         self_ty: ty::Ty<'tcx>,
                         segment: &hir::PathSegment,
                         span: Span,
                         call_expr: &'gcx hir::Expr,
                         self_expr: &'gcx hir::Expr)
                         -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
        debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
               segment.name,
               self_ty,
               call_expr,
               self_expr);

        let pick = self.lookup_probe(
            span,
            segment.name,
            self_ty,
            call_expr,
            ProbeScope::TraitsInScope
        )?;

        if let Some(import_id) = pick.import_id {
            let import_def_id = self.tcx.hir.local_def_id(import_id);
            debug!("used_trait_import: {:?}", import_def_id);
            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
        }

        self.tcx.check_stability(pick.item.def_id, call_expr.id, span);

        let result = self.confirm_method(span,
                                         self_expr,
                                         call_expr,
                                         self_ty,
                                         pick.clone(),
                                         segment);

        if result.rerun {
            // We probe again, taking all traits into account (not only those in scope).
            if let Ok(new_pick) = self.lookup_probe(span,
                                                    segment.name,
                                                    self_ty,
                                                    call_expr,
                                                    ProbeScope::AllTraits) {
                // If we find a different result, the caller probably forgot to import the trait.
                // We span an error with an appropriate help message.
                if new_pick != pick {
                    let error = MethodError::NoMatch(
                        NoMatchData::new(Vec::new(),
                                         Vec::new(),
                                         vec![new_pick.item.container.id()],
                                         probe::Mode::MethodCall)
                    );
                    self.report_method_error(span,
                                             self_ty,
                                             segment.name,
                                             Some(self_expr),
                                             error,
                                             None);
                }
            }
        }

        Ok(result.callee)
    }

    fn lookup_probe(&self,
                    span: Span,
                    method_name: ast::Name,
                    self_ty: ty::Ty<'tcx>,
                    call_expr: &'gcx hir::Expr,
                    scope: ProbeScope)
                    -> probe::PickResult<'tcx> {
        let mode = probe::Mode::MethodCall;
        let self_ty = self.resolve_type_vars_if_possible(&self_ty);
        self.probe_for_name(span, mode, method_name, IsSuggestion(false),
                            self_ty, call_expr.id, scope)
    }

    /// `lookup_method_in_trait` is used for overloaded operators.
    /// It does a very narrow slice of what the normal probe/confirm path does.
    /// In particular, it doesn't really do any probing: it simply constructs
    /// an obligation for aparticular trait with the given self-type and checks
    /// whether that trait is implemented.
    ///
    /// FIXME(#18741) -- It seems likely that we can consolidate some of this
    /// code with the other method-lookup code. In particular, the second half
    /// of this method is basically the same as confirmation.
    pub fn lookup_method_in_trait(&self,
                                  span: Span,
                                  m_name: ast::Name,
                                  trait_def_id: DefId,
                                  self_ty: ty::Ty<'tcx>,
                                  opt_input_types: Option<&[ty::Ty<'tcx>]>)
                                  -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
        debug!("lookup_in_trait_adjusted(self_ty={:?}, \
                m_name={}, trait_def_id={:?})",
               self_ty,
               m_name,
               trait_def_id);

        // Construct a trait-reference `self_ty : Trait<input_tys>`
        let substs = Substs::for_item(self.tcx,
                                      trait_def_id,
                                      |def, _| self.region_var_for_def(span, def),
                                      |def, substs| {
            if def.index == 0 {
                self_ty
            } else if let Some(ref input_types) = opt_input_types {
                input_types[def.index as usize - 1]
            } else {
                self.type_var_for_def(span, def, substs)
            }
        });

        let trait_ref = ty::TraitRef::new(trait_def_id, substs);

        // Construct an obligation
        let poly_trait_ref = trait_ref.to_poly_trait_ref();
        let obligation =
            traits::Obligation::misc(span,
                                     self.body_id,
                                     self.param_env,
                                     poly_trait_ref.to_predicate());

        // Now we want to know if this can be matched
        let mut selcx = traits::SelectionContext::new(self);
        if !selcx.evaluate_obligation(&obligation) {
            debug!("--> Cannot match obligation");
            return None; // Cannot be matched, no such method resolution is possible.
        }

        // Trait must have a method named `m_name` and it should not have
        // type parameters or early-bound regions.
        let tcx = self.tcx;
        let method_item = self.associated_item(trait_def_id, m_name).unwrap();
        let def_id = method_item.def_id;
        let generics = tcx.generics_of(def_id);
        assert_eq!(generics.types.len(), 0);
        assert_eq!(generics.regions.len(), 0);

        debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
        let mut obligations = vec![];

        // Instantiate late-bound regions and substitute the trait
        // parameters into the method type to get the actual method type.
        //
        // NB: Instantiate late-bound regions first so that
        // `instantiate_type_scheme` can normalize associated types that
        // may reference those regions.
        let fn_sig = tcx.fn_sig(def_id);
        let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
                                                                    infer::FnCall,
                                                                    &fn_sig).0;
        let fn_sig = fn_sig.subst(self.tcx, substs);
        let fn_sig = match self.normalize_associated_types_in_as_infer_ok(span, &fn_sig) {
            InferOk { value, obligations: o } => {
                obligations.extend(o);
                value
            }
        };

        // Register obligations for the parameters.  This will include the
        // `Self` parameter, which in turn has a bound of the main trait,
        // so this also effectively registers `obligation` as well.  (We
        // used to register `obligation` explicitly, but that resulted in
        // double error messages being reported.)
        //
        // Note that as the method comes from a trait, it should not have
        // any late-bound regions appearing in its bounds.
        let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
        let bounds = match self.normalize_associated_types_in_as_infer_ok(span, &bounds) {
            InferOk { value, obligations: o } => {
                obligations.extend(o);
                value
            }
        };
        assert!(!bounds.has_escaping_regions());

        let cause = traits::ObligationCause::misc(span, self.body_id);
        obligations.extend(traits::predicates_for_generics(cause.clone(),
                                                           self.param_env,
                                                           &bounds));

        // Also add an obligation for the method type being well-formed.
        let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig));
        debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
               method_ty,
               obligation);
        obligations.push(traits::Obligation::new(cause,
                                                 self.param_env,
                                                 ty::Predicate::WellFormed(method_ty)));

        let callee = MethodCallee {
            def_id: def_id,
            substs: trait_ref.substs,
            sig: fn_sig,
        };

        debug!("callee = {:?}", callee);

        Some(InferOk {
            obligations,
            value: callee
        })
    }

    pub fn resolve_ufcs(&self,
                        span: Span,
                        method_name: ast::Name,
                        self_ty: ty::Ty<'tcx>,
                        expr_id: ast::NodeId)
                        -> Result<Def, MethodError<'tcx>> {
        let mode = probe::Mode::Path;
        let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
                                       self_ty, expr_id, ProbeScope::TraitsInScope)?;

        if let Some(import_id) = pick.import_id {
            let import_def_id = self.tcx.hir.local_def_id(import_id);
            debug!("used_trait_import: {:?}", import_def_id);
            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
        }

        let def = pick.item.def();
        self.tcx.check_stability(def.def_id(), expr_id, span);

        Ok(def)
    }

    /// Find item with name `item_name` defined in impl/trait `def_id`
    /// and return it, or `None`, if no such item was defined there.
    pub fn associated_item(&self, def_id: DefId, item_name: ast::Name)
                           -> Option<ty::AssociatedItem> {
        let ident = self.tcx.adjust(item_name, def_id, self.body_id).0;
        self.tcx.associated_items(def_id).find(|item| item.name.to_ident() == ident)
    }
}
<commit_msg>Handle ambiguous cases<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Method lookup: the secret sauce of Rust. See `README.md`.

use check::FnCtxt;
use hir::def::Def;
use hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::traits;
use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
use rustc::ty::subst::Subst;
use rustc::infer::{self, InferOk};

use syntax::ast;
use syntax_pos::Span;

use rustc::hir;

pub use self::MethodError::*;
pub use self::CandidateSource::*;

pub use self::suggest::AllTraitsVec;

mod confirm;
pub mod probe;
mod suggest;

use self::probe::{IsSuggestion, ProbeScope};

#[derive(Clone, Copy, Debug)]
pub struct MethodCallee<'tcx> {
    /// Impl method ID, for inherent methods, or trait method ID, otherwise.
    pub def_id: DefId,
    pub substs: &'tcx Substs<'tcx>,

    /// Instantiated method signature, i.e. it has been
    /// substituted, normalized, and has had late-bound
    /// lifetimes replaced with inference variables.
    pub sig: ty::FnSig<'tcx>,
}

pub enum MethodError<'tcx> {
    // Did not find an applicable method, but we did find various near-misses that may work.
    NoMatch(NoMatchData<'tcx>),

    // Multiple methods might apply.
    Ambiguity(Vec<CandidateSource>),

    // Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind.
    ClosureAmbiguity(// DefId of fn trait
                     DefId),

    // Found an applicable method, but it is not visible.
    PrivateMatch(Def),
}

// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
pub struct NoMatchData<'tcx> {
    pub static_candidates: Vec<CandidateSource>,
    pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
    pub out_of_scope_traits: Vec<DefId>,
    pub mode: probe::Mode,
}

impl<'tcx> NoMatchData<'tcx> {
    pub fn new(static_candidates: Vec<CandidateSource>,
               unsatisfied_predicates: Vec<TraitRef<'tcx>>,
               out_of_scope_traits: Vec<DefId>,
               mode: probe::Mode)
               -> Self {
        NoMatchData {
            static_candidates: static_candidates,
            unsatisfied_predicates: unsatisfied_predicates,
            out_of_scope_traits: out_of_scope_traits,
            mode: mode,
        }
    }
}

// A pared down enum describing just the places from which a method
// candidate can arise. Used for error reporting only.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum CandidateSource {
    ImplSource(DefId),
    TraitSource(// trait id
                DefId),
}

impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
    /// Determines whether the type `self_ty` supports a method name `method_name` or not.
    pub fn method_exists(&self,
                         span: Span,
                         method_name: ast::Name,
                         self_ty: ty::Ty<'tcx>,
                         call_expr_id: ast::NodeId,
                         allow_private: bool)
                         -> bool {
        let mode = probe::Mode::MethodCall;
        match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
                                  self_ty, call_expr_id, ProbeScope::TraitsInScope) {
            Ok(..) => true,
            Err(NoMatch(..)) => false,
            Err(Ambiguity(..)) => true,
            Err(ClosureAmbiguity(..)) => true,
            Err(PrivateMatch(..)) => allow_private,
        }
    }

    /// Performs method lookup. If lookup is successful, it will return the callee
    /// and store an appropriate adjustment for the self-expr. In some cases it may
    /// report an error (e.g., invoking the `drop` method).
    ///
    /// # Arguments
    ///
    /// Given a method call like `foo.bar::<T1,...Tn>(...)`:
    ///
    /// * `fcx`:                   the surrounding `FnCtxt` (!)
    /// * `span`:                  the span for the method call
    /// * `method_name`:           the name of the method being called (`bar`)
    /// * `self_ty`:               the (unadjusted) type of the self expression (`foo`)
    /// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`)
    /// * `self_expr`:             the self expression (`foo`)
    pub fn lookup_method(&self,
                         self_ty: ty::Ty<'tcx>,
                         segment: &hir::PathSegment,
                         span: Span,
                         call_expr: &'gcx hir::Expr,
                         self_expr: &'gcx hir::Expr)
                         -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
        debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
               segment.name,
               self_ty,
               call_expr,
               self_expr);

        let pick = self.lookup_probe(
            span,
            segment.name,
            self_ty,
            call_expr,
            ProbeScope::TraitsInScope
        )?;

        if let Some(import_id) = pick.import_id {
            let import_def_id = self.tcx.hir.local_def_id(import_id);
            debug!("used_trait_import: {:?}", import_def_id);
            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
        }

        self.tcx.check_stability(pick.item.def_id, call_expr.id, span);

        let result = self.confirm_method(span,
                                         self_expr,
                                         call_expr,
                                         self_ty,
                                         pick.clone(),
                                         segment);

        if result.rerun {
            // We probe again, taking all traits into account (not only those in scope).
            let candidates =
                match self.lookup_probe(span,
                                        segment.name,
                                        self_ty,
                                        call_expr,
                                        ProbeScope::AllTraits) {
                    Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
                    Err(MethodError::Ambiguity(ref sources)) => {
                        sources.iter()
                               .filter_map(|source| {
                                   match *source {
                                       // Note: this cannot come from an inherent impl,
                                       // because the first probe succeeded.
                                       ImplSource(def) => self.tcx.trait_id_of_impl(def),
                                       TraitSource(_) => None,
                                   }
                               })
                               .collect()
                    }
                    _ => Vec::new(),
                };

            // If we find a different result, the caller probably forgot to import a trait.
            // We span an error with an appropriate help message.
            if !candidates.is_empty() {
                let error = MethodError::NoMatch(
                    NoMatchData::new(Vec::new(), Vec::new(), candidates, probe::Mode::MethodCall)
                );
                self.report_method_error(span,
                                         self_ty,
                                         segment.name,
                                         Some(self_expr),
                                         error,
                                         None);
            }
        }

        Ok(result.callee)
    }

    fn lookup_probe(&self,
                    span: Span,
                    method_name: ast::Name,
                    self_ty: ty::Ty<'tcx>,
                    call_expr: &'gcx hir::Expr,
                    scope: ProbeScope)
                    -> probe::PickResult<'tcx> {
        let mode = probe::Mode::MethodCall;
        let self_ty = self.resolve_type_vars_if_possible(&self_ty);
        self.probe_for_name(span, mode, method_name, IsSuggestion(false),
                            self_ty, call_expr.id, scope)
    }

    /// `lookup_method_in_trait` is used for overloaded operators.
    /// It does a very narrow slice of what the normal probe/confirm path does.
    /// In particular, it doesn't really do any probing: it simply constructs
    /// an obligation for aparticular trait with the given self-type and checks
    /// whether that trait is implemented.
    ///
    /// FIXME(#18741) -- It seems likely that we can consolidate some of this
    /// code with the other method-lookup code. In particular, the second half
    /// of this method is basically the same as confirmation.
    pub fn lookup_method_in_trait(&self,
                                  span: Span,
                                  m_name: ast::Name,
                                  trait_def_id: DefId,
                                  self_ty: ty::Ty<'tcx>,
                                  opt_input_types: Option<&[ty::Ty<'tcx>]>)
                                  -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
        debug!("lookup_in_trait_adjusted(self_ty={:?}, \
                m_name={}, trait_def_id={:?})",
               self_ty,
               m_name,
               trait_def_id);

        // Construct a trait-reference `self_ty : Trait<input_tys>`
        let substs = Substs::for_item(self.tcx,
                                      trait_def_id,
                                      |def, _| self.region_var_for_def(span, def),
                                      |def, substs| {
            if def.index == 0 {
                self_ty
            } else if let Some(ref input_types) = opt_input_types {
                input_types[def.index as usize - 1]
            } else {
                self.type_var_for_def(span, def, substs)
            }
        });

        let trait_ref = ty::TraitRef::new(trait_def_id, substs);

        // Construct an obligation
        let poly_trait_ref = trait_ref.to_poly_trait_ref();
        let obligation =
            traits::Obligation::misc(span,
                                     self.body_id,
                                     self.param_env,
                                     poly_trait_ref.to_predicate());

        // Now we want to know if this can be matched
        let mut selcx = traits::SelectionContext::new(self);
        if !selcx.evaluate_obligation(&obligation) {
            debug!("--> Cannot match obligation");
            return None; // Cannot be matched, no such method resolution is possible.
        }

        // Trait must have a method named `m_name` and it should not have
        // type parameters or early-bound regions.
        let tcx = self.tcx;
        let method_item = self.associated_item(trait_def_id, m_name).unwrap();
        let def_id = method_item.def_id;
        let generics = tcx.generics_of(def_id);
        assert_eq!(generics.types.len(), 0);
        assert_eq!(generics.regions.len(), 0);

        debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
        let mut obligations = vec![];

        // Instantiate late-bound regions and substitute the trait
        // parameters into the method type to get the actual method type.
        //
        // NB: Instantiate late-bound regions first so that
        // `instantiate_type_scheme` can normalize associated types that
        // may reference those regions.
        let fn_sig = tcx.fn_sig(def_id);
        let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
                                                                    infer::FnCall,
                                                                    &fn_sig).0;
        let fn_sig = fn_sig.subst(self.tcx, substs);
        let fn_sig = match self.normalize_associated_types_in_as_infer_ok(span, &fn_sig) {
            InferOk { value, obligations: o } => {
                obligations.extend(o);
                value
            }
        };

        // Register obligations for the parameters.  This will include the
        // `Self` parameter, which in turn has a bound of the main trait,
        // so this also effectively registers `obligation` as well.  (We
        // used to register `obligation` explicitly, but that resulted in
        // double error messages being reported.)
        //
        // Note that as the method comes from a trait, it should not have
        // any late-bound regions appearing in its bounds.
        let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
        let bounds = match self.normalize_associated_types_in_as_infer_ok(span, &bounds) {
            InferOk { value, obligations: o } => {
                obligations.extend(o);
                value
            }
        };
        assert!(!bounds.has_escaping_regions());

        let cause = traits::ObligationCause::misc(span, self.body_id);
        obligations.extend(traits::predicates_for_generics(cause.clone(),
                                                           self.param_env,
                                                           &bounds));

        // Also add an obligation for the method type being well-formed.
        let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig));
        debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
               method_ty,
               obligation);
        obligations.push(traits::Obligation::new(cause,
                                                 self.param_env,
                                                 ty::Predicate::WellFormed(method_ty)));

        let callee = MethodCallee {
            def_id: def_id,
            substs: trait_ref.substs,
            sig: fn_sig,
        };

        debug!("callee = {:?}", callee);

        Some(InferOk {
            obligations,
            value: callee
        })
    }

    pub fn resolve_ufcs(&self,
                        span: Span,
                        method_name: ast::Name,
                        self_ty: ty::Ty<'tcx>,
                        expr_id: ast::NodeId)
                        -> Result<Def, MethodError<'tcx>> {
        let mode = probe::Mode::Path;
        let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
                                       self_ty, expr_id, ProbeScope::TraitsInScope)?;

        if let Some(import_id) = pick.import_id {
            let import_def_id = self.tcx.hir.local_def_id(import_id);
            debug!("used_trait_import: {:?}", import_def_id);
            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
        }

        let def = pick.item.def();
        self.tcx.check_stability(def.def_id(), expr_id, span);

        Ok(def)
    }

    /// Find item with name `item_name` defined in impl/trait `def_id`
    /// and return it, or `None`, if no such item was defined there.
    pub fn associated_item(&self, def_id: DefId, item_name: ast::Name)
                           -> Option<ty::AssociatedItem> {
        let ident = self.tcx.adjust(item_name, def_id, self.body_id).0;
        self.tcx.associated_items(def_id).find(|item| item.name.to_ident() == ident)
    }
}
<|endoftext|>


<commit_before><commit_msg>feat: trait default behave<commit_after><|endoftext|>


<commit_before><commit_msg>Added unit tests for three more testnet failures, the latter of which I'm still working on<commit_after><|endoftext|>


<commit_before><commit_msg>Create functions for getting config filenames<commit_after>//! System functions for `budget`

/// Acquire the home directory's path
fn get_homedir_string() -> Option<String> {
    use std::env;
    // Attempt to retrieve the home directory, if we fail, return None
    match env::home_dir() {
        // Take the homedir path, convert it to a string, and append the filename
        Some(path) => Some(String::from(
                path.to_string_lossy().into_owned())),
        None => None
    }
}

/// Acquire the path to the config file
pub fn get_config_file_name(file_name: &str) -> Option<String> {
    // TODO: Reimplement this to not suck

    // Try getting the home directory string, and concatenate it with the filename
    match get_homedir_string() {
        Some(path) => Some(path + "/" + &file_name),
        None => None
    }
}

<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::vec::Vec;

use uuid::Uuid;

use super::super::engine::{Filesystem, HasName, HasUuid, Pool};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::structures::Table;
use super::super::types::{FilesystemUuid, PoolUuid, RenameAction, Redundancy};

use super::blockdev::SimDev;
use super::filesystem::SimFilesystem;
use super::randomization::Randomizer;

#[derive(Debug)]
pub struct SimPool {
    name: String,
    pool_uuid: PoolUuid,
    pub block_devs: HashMap<PathBuf, SimDev>,
    pub filesystems: Table<SimFilesystem>,
    redundancy: Redundancy,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimPool {
    pub fn new(rdm: Rc<RefCell<Randomizer>>,
               name: &str,
               paths: &[&Path],
               redundancy: Redundancy)
               -> SimPool {

        let devices: HashSet<_, RandomState> = HashSet::from_iter(paths);
        let device_pairs = devices
            .iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        let new_pool = SimPool {
            name: name.to_owned(),
            pool_uuid: Uuid::new_v4(),
            block_devs: HashMap::from_iter(device_pairs),
            filesystems: Table::default(),
            redundancy: redundancy,
            rdm: rdm.clone(),
        };

        new_pool
    }

    pub fn check(&mut self) -> () {}
}

impl Pool for SimPool {
    fn add_blockdevs(&mut self, paths: &[&Path], _force: bool) -> EngineResult<Vec<PathBuf>> {
        let rdm = self.rdm.clone();
        let devices: HashSet<_, RandomState> = HashSet::from_iter(paths);
        let device_pairs = devices
            .iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        self.block_devs.extend(device_pairs);
        Ok(devices.iter().map(|d| d.to_path_buf()).collect())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        destroy_filesystems!{self; fs_uuids}
    }

    fn destroy(self) -> EngineResult<()> {
        // Nothing to do here.
        Ok(())
    }

    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let new_filesystem = SimFilesystem::new(uuid, name);
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for SimPool {
    fn uuid(&self) -> &PoolUuid {
        &self.pool_uuid
    }
}

impl HasName for SimPool {
    fn name(&self) -> &str {
        &self.name
    }
}

#[cfg(test)]
mod tests {

    use std::path::Path;

    use uuid::Uuid;

    use engine::Engine;
    use engine::ErrorEnum;
    use engine::EngineError;
    use engine::RenameAction;

    use super::super::SimEngine;

    #[test]
    /// Renaming a filesystem on an empty pool always works
    fn rename_empty() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.rename_filesystem(&Uuid::new_v4(), "new_name") {
                    Ok(RenameAction::NoSource) => true,
                    _ => false,
                });
    }

    #[test]
    /// Renaming a filesystem to another filesystem should work if new name not taken
    fn rename_happens() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        let infos = pool.create_filesystems(&["old_name"]).unwrap();
        assert!(match pool.rename_filesystem(&infos[0].1, "new_name") {
                    Ok(RenameAction::Renamed) => true,
                    _ => false,
                });
    }

    #[test]
    /// Renaming a filesystem to another filesystem should fail if new name taken
    fn rename_fails() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        let results = pool.create_filesystems(&[old_name, new_name]).unwrap();
        let old_uuid = results.iter().find(|x| x.0 == old_name).unwrap().1;
        assert!(match pool.rename_filesystem(&old_uuid, new_name) {
                    Err(EngineError::Engine(ErrorEnum::AlreadyExists, _)) => true,
                    _ => false,
                });
    }

    #[test]
    /// Renaming should succeed if old_name absent, new present
    fn rename_no_op() {
        let new_name = "new_name";
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        pool.create_filesystems(&[new_name]).unwrap();
        assert!(match pool.rename_filesystem(&Uuid::new_v4(), new_name) {
                    Ok(RenameAction::NoSource) => true,
                    _ => false,
                });
    }

    #[test]
    /// Removing an empty list of filesystems should always succeed
    fn destroy_fs_empty() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.destroy_filesystems(&[]) {
                    Ok(names) => names.is_empty(),
                    _ => false,
                });
    }

    #[test]
    /// Removing a non-empty list of filesystems should succeed on empty pool
    fn destroy_fs_some() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(pool.destroy_filesystems(&[&Uuid::new_v4()]).is_ok());
    }

    #[test]
    /// Removing a non-empty list of filesystems should succeed on any pool
    fn destroy_fs_any() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        let fs_results = pool.create_filesystems(&["fs_name"]).unwrap();
        let fs_uuid = fs_results[0].1;
        assert!(match pool.destroy_filesystems(&[&fs_uuid, &Uuid::new_v4()]) {
                    Ok(filesystems) => filesystems == vec![&fs_uuid],
                    _ => false,
                });
    }

    #[test]
    /// Creating an empty list of filesystems should succeed, always
    fn create_fs_none() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.create_filesystems(&[]) {
                    Ok(names) => names.is_empty(),
                    _ => false,
                });
    }

    #[test]
    /// Creating a non-empty list of filesystems always succeeds.
    fn create_fs_some() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.create_filesystems(&["name"]) {
                    Ok(names) => (names.len() == 1) & (names[0].0 == "name"),
                    _ => false,
                });
    }

    #[test]
    /// Creating a an already existing filesystem fails.
    fn create_fs_conflict() {
        let fs_name = "fs_name";
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        pool.create_filesystems(&[fs_name]).unwrap();
        assert!(match pool.create_filesystems(&[fs_name]) {
                    Err(EngineError::Engine(ErrorEnum::AlreadyExists, _)) => true,
                    _ => false,
                });
    }

    #[test]
    /// Requesting identical filesystems succeeds.
    fn create_fs_dups() {
        let fs_name = "fs_name";
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.create_filesystems(&[fs_name, fs_name]) {
                    Ok(names) => (names.len() == 1) & (names[0].0 == fs_name),
                    _ => false,
                });
    }

    #[test]
    /// Adding a list of devices to an empty pool should yield list.
    fn add_device_empty() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        let devices = [Path::new("/s/a"), Path::new("/s/b")];
        assert!(match pool.add_blockdevs(&devices, false) {
                    Ok(devs) => devs.len() == devices.len(),
                    _ => false,
                });
    }
}
<commit_msg>Remove unnecessary let-statement<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::vec::Vec;

use uuid::Uuid;

use super::super::engine::{Filesystem, HasName, HasUuid, Pool};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::structures::Table;
use super::super::types::{FilesystemUuid, PoolUuid, RenameAction, Redundancy};

use super::blockdev::SimDev;
use super::filesystem::SimFilesystem;
use super::randomization::Randomizer;

#[derive(Debug)]
pub struct SimPool {
    name: String,
    pool_uuid: PoolUuid,
    pub block_devs: HashMap<PathBuf, SimDev>,
    pub filesystems: Table<SimFilesystem>,
    redundancy: Redundancy,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimPool {
    pub fn new(rdm: Rc<RefCell<Randomizer>>,
               name: &str,
               paths: &[&Path],
               redundancy: Redundancy)
               -> SimPool {

        let devices: HashSet<_, RandomState> = HashSet::from_iter(paths);
        let device_pairs = devices
            .iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        SimPool {
            name: name.to_owned(),
            pool_uuid: Uuid::new_v4(),
            block_devs: HashMap::from_iter(device_pairs),
            filesystems: Table::default(),
            redundancy: redundancy,
            rdm: rdm.clone(),
        }
    }

    pub fn check(&mut self) -> () {}
}

impl Pool for SimPool {
    fn add_blockdevs(&mut self, paths: &[&Path], _force: bool) -> EngineResult<Vec<PathBuf>> {
        let rdm = self.rdm.clone();
        let devices: HashSet<_, RandomState> = HashSet::from_iter(paths);
        let device_pairs = devices
            .iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        self.block_devs.extend(device_pairs);
        Ok(devices.iter().map(|d| d.to_path_buf()).collect())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        destroy_filesystems!{self; fs_uuids}
    }

    fn destroy(self) -> EngineResult<()> {
        // Nothing to do here.
        Ok(())
    }

    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let new_filesystem = SimFilesystem::new(uuid, name);
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for SimPool {
    fn uuid(&self) -> &PoolUuid {
        &self.pool_uuid
    }
}

impl HasName for SimPool {
    fn name(&self) -> &str {
        &self.name
    }
}

#[cfg(test)]
mod tests {

    use std::path::Path;

    use uuid::Uuid;

    use engine::Engine;
    use engine::ErrorEnum;
    use engine::EngineError;
    use engine::RenameAction;

    use super::super::SimEngine;

    #[test]
    /// Renaming a filesystem on an empty pool always works
    fn rename_empty() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.rename_filesystem(&Uuid::new_v4(), "new_name") {
                    Ok(RenameAction::NoSource) => true,
                    _ => false,
                });
    }

    #[test]
    /// Renaming a filesystem to another filesystem should work if new name not taken
    fn rename_happens() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        let infos = pool.create_filesystems(&["old_name"]).unwrap();
        assert!(match pool.rename_filesystem(&infos[0].1, "new_name") {
                    Ok(RenameAction::Renamed) => true,
                    _ => false,
                });
    }

    #[test]
    /// Renaming a filesystem to another filesystem should fail if new name taken
    fn rename_fails() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        let results = pool.create_filesystems(&[old_name, new_name]).unwrap();
        let old_uuid = results.iter().find(|x| x.0 == old_name).unwrap().1;
        assert!(match pool.rename_filesystem(&old_uuid, new_name) {
                    Err(EngineError::Engine(ErrorEnum::AlreadyExists, _)) => true,
                    _ => false,
                });
    }

    #[test]
    /// Renaming should succeed if old_name absent, new present
    fn rename_no_op() {
        let new_name = "new_name";
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        pool.create_filesystems(&[new_name]).unwrap();
        assert!(match pool.rename_filesystem(&Uuid::new_v4(), new_name) {
                    Ok(RenameAction::NoSource) => true,
                    _ => false,
                });
    }

    #[test]
    /// Removing an empty list of filesystems should always succeed
    fn destroy_fs_empty() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.destroy_filesystems(&[]) {
                    Ok(names) => names.is_empty(),
                    _ => false,
                });
    }

    #[test]
    /// Removing a non-empty list of filesystems should succeed on empty pool
    fn destroy_fs_some() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(pool.destroy_filesystems(&[&Uuid::new_v4()]).is_ok());
    }

    #[test]
    /// Removing a non-empty list of filesystems should succeed on any pool
    fn destroy_fs_any() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine.create_pool("name", &[], None, false).unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        let fs_results = pool.create_filesystems(&["fs_name"]).unwrap();
        let fs_uuid = fs_results[0].1;
        assert!(match pool.destroy_filesystems(&[&fs_uuid, &Uuid::new_v4()]) {
                    Ok(filesystems) => filesystems == vec![&fs_uuid],
                    _ => false,
                });
    }

    #[test]
    /// Creating an empty list of filesystems should succeed, always
    fn create_fs_none() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.create_filesystems(&[]) {
                    Ok(names) => names.is_empty(),
                    _ => false,
                });
    }

    #[test]
    /// Creating a non-empty list of filesystems always succeeds.
    fn create_fs_some() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.create_filesystems(&["name"]) {
                    Ok(names) => (names.len() == 1) & (names[0].0 == "name"),
                    _ => false,
                });
    }

    #[test]
    /// Creating a an already existing filesystem fails.
    fn create_fs_conflict() {
        let fs_name = "fs_name";
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        pool.create_filesystems(&[fs_name]).unwrap();
        assert!(match pool.create_filesystems(&[fs_name]) {
                    Err(EngineError::Engine(ErrorEnum::AlreadyExists, _)) => true,
                    _ => false,
                });
    }

    #[test]
    /// Requesting identical filesystems succeeds.
    fn create_fs_dups() {
        let fs_name = "fs_name";
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        assert!(match pool.create_filesystems(&[fs_name, fs_name]) {
                    Ok(names) => (names.len() == 1) & (names[0].0 == fs_name),
                    _ => false,
                });
    }

    #[test]
    /// Adding a list of devices to an empty pool should yield list.
    fn add_device_empty() {
        let mut engine = SimEngine::default();
        let (uuid, _) = engine
            .create_pool("pool_name", &[], None, false)
            .unwrap();
        let pool = engine.get_pool(&uuid).unwrap();
        let devices = [Path::new("/s/a"), Path::new("/s/b")];
        assert!(match pool.add_blockdevs(&devices, false) {
                    Ok(devs) => devs.len() == devices.len(),
                    _ => false,
                });
    }
}
<|endoftext|>


<commit_before><commit_msg>Adding rot<commit_after>
/// Rotation
pub struct Rot {
    pub s: f32,
    pub c: f32
}

impl Rot {
    pub fn new() -> Rot {
        Rot {
            s: 0.0,
            c: 1.0
        }
    }

    /// Initialize from an angle in radians
    pub fn new_angle(angle: f32) -> Rot {
        Rot {
            s: angle.sin(),
            c: angle.cos()
        }
    }

    pub fn set(&mut self, angle: f32) {
        self.s = angle.sin();
        self.c = angle.cos();
    }

    /// Set to the identity rotation
    pub fn set_identity(&mut self) {
        self.s = 0.0;
        self.c = 1.0;
    }

    /// Get the angle in radians
    pub fn get_angle() -> f32 {
        s.atan2(c)
    }

    /// Get the x-axis
    pub fn get_x_axis(&mut self) -> Vec2 {
        Vec2::new(self.c, self.s)
    }

    /// Get the u axis
    pub fn get_y_axis(&mut self) -> Vec2 {
        Vec2::new(-self.s, self.c)
    }
}
<|endoftext|>


<commit_before><commit_msg>multiline closures added<commit_after><|endoftext|>


<commit_before><commit_msg>dynamic dispatch in closures as traits<commit_after><|endoftext|>


<commit_before><commit_msg>added todo<commit_after><|endoftext|>


<commit_before><commit_msg> removed filter for testing<commit_after><|endoftext|>


<commit_before><commit_msg>an empy message<commit_after><|endoftext|>


<commit_before><commit_msg>Disable SPIR-V optimiser as the water tessellation shader fails to optimise on Linux (issue #47)<commit_after><|endoftext|>


<commit_before><commit_msg>function pointers added to closure<commit_after><|endoftext|>