<commit_before>// Copyright 2013 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.

/*! rustc compiler intrinsics.

The corresponding definitions are in librustc/middle/trans/foreign.rs.

# Atomics

The atomic intrinsics provide common atomic operations on machine
words, with multiple possible memory orderings. They obey the same
semantics as C++0x. See the LLVM documentation on [[atomics]].

[atomics]: http://llvm.org/docs/Atomics.html

A quick refresher on memory ordering:

* Acquire - a barrier for aquiring a lock. Subsequent reads and writes
  take place after the barrier.
* Release - a barrier for releasing a lock. Preceding reads and writes
  take place before the barrier.
* Sequentially consistent - sequentially consistent operations are
  guaranteed to happen in order. This is the standard mode for working
  with atomic types and is equivalent to Java's `volatile`.

*/
#[abi = "rust-intrinsic"]
pub extern "rust-intrinsic" {

    /// Atomic compare and exchange, sequentially consistent.
    pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
    /// Atomic compare and exchange, acquire ordering.
    pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
    /// Atomic compare and exchange, release ordering.
    pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;

    /// Atomic load, sequentially consistent.
    pub fn atomic_load(src: &int) -> int;
    /// Atomic load, acquire ordering.
    pub fn atomic_load_acq(src: &int) -> int;

    /// Atomic store, sequentially consistent.
    pub fn atomic_store(dst: &mut int, val: int);
    /// Atomic store, release ordering.
    pub fn atomic_store_rel(dst: &mut int, val: int);

    /// Atomic exchange, sequentially consistent.
    pub fn atomic_xchg(dst: &mut int, src: int) -> int;
    /// Atomic exchange, acquire ordering.
    pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int;
    /// Atomic exchange, release ordering.
    pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int;

    /// Atomic addition, sequentially consistent.
    pub fn atomic_xadd(dst: &mut int, src: int) -> int;
    /// Atomic addition, acquire ordering.
    pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int;
    /// Atomic addition, release ordering.
    pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int;

    /// Atomic subtraction, sequentially consistent.
    pub fn atomic_xsub(dst: &mut int, src: int) -> int;
    /// Atomic subtraction, acquire ordering.
    pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int;
    /// Atomic subtraction, release ordering.
    pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int;

    /// The size of a type in bytes.
    ///
    /// This is the exact number of bytes in memory taken up by a
    /// value of the given type. In other words, a memset of this size
    /// would *exactly* overwrite a value. When laid out in vectors
    /// and structures there may be additional padding between
    /// elements.
    pub fn size_of<T>() -> uint;

    /// Move a value to a memory location containing a value.
    ///
    /// Drop glue is run on the destination, which must contain a
    /// valid Rust value.
    pub fn move_val<T>(dst: &mut T, src: T);

    /// Move a value to an uninitialized memory location.
    ///
    /// Drop glue is not run on the destination.
    pub fn move_val_init<T>(dst: &mut T, src: T);

    pub fn min_align_of<T>() -> uint;
    pub fn pref_align_of<T>() -> uint;

    /// Get a static pointer to a type descriptor.
    pub fn get_tydesc<T>() -> *();

    /// Create a value initialized to zero.
    ///
    /// `init` is unsafe because it returns a zeroed-out datum,
    /// which is unsafe unless T is POD. We don't have a POD
    /// kind yet. (See #4074).
    pub unsafe fn init<T>() -> T;

    /// Create an uninitialized value.
    pub unsafe fn uninit<T>() -> T;

    /// Move a value out of scope without running drop glue.
    ///
    /// `forget` is unsafe because the caller is responsible for
    /// ensuring the argument is deallocated already.
    pub unsafe fn forget<T>(_: T) -> ();
    pub fn transmute<T,U>(e: T) -> U;

    /// Returns `true` if a type requires drop glue.
    pub fn needs_drop<T>() -> bool;

    // XXX: intrinsic uses legacy modes and has reference to TyDesc
    // and TyVisitor which are in librustc
    //fn visit_tydesc(++td: *TyDesc, &&tv: TyVisitor) -> ();

    pub fn frame_address(f: &once fn(*u8));

    /// Get the address of the `__morestack` stack growth function.
    pub fn morestack_addr() -> *();

    /// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
    /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
    #[cfg(not(stage0))]
    pub fn memcpy32<T>(dst: *mut T, src: *T, count: u32);
    /// Equivalent to the `llvm.memcpy.p0i8.0i8.i64` intrinsic, with a size of
    /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
    #[cfg(not(stage0))]
    pub fn memcpy64<T>(dst: *mut T, src: *T, count: u64);

    /// Equivalent to the `llvm.memmove.p0i8.0i8.i32` intrinsic.
    #[cfg(stage0)]
    pub fn memmove32(dst: *mut u8, src: *u8, size: u32);
    /// Equivalent to the `llvm.memmove.p0i8.0i8.i64` intrinsic.
    #[cfg(stage0)]
    pub fn memmove64(dst: *mut u8, src: *u8, size: u64);

    /// Equivalent to the `llvm.memmove.p0i8.0i8.i32` intrinsic, with a size of
    /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
    #[cfg(not(stage0))]
    pub fn memmove32<T>(dst: *mut T, src: *T, count: u32);
    /// Equivalent to the `llvm.memmove.p0i8.0i8.i64` intrinsic, with a size of
    /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
    #[cfg(not(stage0))]
    pub fn memmove64<T>(dst: *mut T, src: *T, count: u64);

    pub fn sqrtf32(x: f32) -> f32;
    pub fn sqrtf64(x: f64) -> f64;

    pub fn powif32(a: f32, x: i32) -> f32;
    pub fn powif64(a: f64, x: i32) -> f64;

    // the following kill the stack canary without
    // `fixed_stack_segment`. This possibly only affects the f64
    // variants, but it's hard to be sure since it seems to only
    // occur with fairly specific arguments.
    #[fixed_stack_segment]
    pub fn sinf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn sinf64(x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn cosf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn cosf64(x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn powf32(a: f32, x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn powf64(a: f64, x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn expf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn expf64(x: f64) -> f64;

    pub fn exp2f32(x: f32) -> f32;
    pub fn exp2f64(x: f64) -> f64;

    pub fn logf32(x: f32) -> f32;
    pub fn logf64(x: f64) -> f64;

    pub fn log10f32(x: f32) -> f32;
    pub fn log10f64(x: f64) -> f64;

    pub fn log2f32(x: f32) -> f32;
    pub fn log2f64(x: f64) -> f64;

    pub fn fmaf32(a: f32, b: f32, c: f32) -> f32;
    pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;

    pub fn fabsf32(x: f32) -> f32;
    pub fn fabsf64(x: f64) -> f64;

    pub fn floorf32(x: f32) -> f32;
    pub fn floorf64(x: f64) -> f64;

    pub fn ceilf32(x: f32) -> f32;
    pub fn ceilf64(x: f64) -> f64;

    pub fn truncf32(x: f32) -> f32;
    pub fn truncf64(x: f64) -> f64;

    pub fn ctpop8(x: i8) -> i8;
    pub fn ctpop16(x: i16) -> i16;
    pub fn ctpop32(x: i32) -> i32;
    pub fn ctpop64(x: i64) -> i64;

    pub fn ctlz8(x: i8) -> i8;
    pub fn ctlz16(x: i16) -> i16;
    pub fn ctlz32(x: i32) -> i32;
    pub fn ctlz64(x: i64) -> i64;

    pub fn cttz8(x: i8) -> i8;
    pub fn cttz16(x: i16) -> i16;
    pub fn cttz32(x: i32) -> i32;
    pub fn cttz64(x: i64) -> i64;

    pub fn bswap16(x: i16) -> i16;
    pub fn bswap32(x: i32) -> i32;
    pub fn bswap64(x: i64) -> i64;
}
<commit_msg>C++0x -> C++11<commit_after>// Copyright 2013 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.

/*! rustc compiler intrinsics.

The corresponding definitions are in librustc/middle/trans/foreign.rs.

# Atomics

The atomic intrinsics provide common atomic operations on machine
words, with multiple possible memory orderings. They obey the same
semantics as C++11. See the LLVM documentation on [[atomics]].

[atomics]: http://llvm.org/docs/Atomics.html

A quick refresher on memory ordering:

* Acquire - a barrier for aquiring a lock. Subsequent reads and writes
  take place after the barrier.
* Release - a barrier for releasing a lock. Preceding reads and writes
  take place before the barrier.
* Sequentially consistent - sequentially consistent operations are
  guaranteed to happen in order. This is the standard mode for working
  with atomic types and is equivalent to Java's `volatile`.

*/
#[abi = "rust-intrinsic"]
pub extern "rust-intrinsic" {

    /// Atomic compare and exchange, sequentially consistent.
    pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
    /// Atomic compare and exchange, acquire ordering.
    pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
    /// Atomic compare and exchange, release ordering.
    pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;

    /// Atomic load, sequentially consistent.
    pub fn atomic_load(src: &int) -> int;
    /// Atomic load, acquire ordering.
    pub fn atomic_load_acq(src: &int) -> int;

    /// Atomic store, sequentially consistent.
    pub fn atomic_store(dst: &mut int, val: int);
    /// Atomic store, release ordering.
    pub fn atomic_store_rel(dst: &mut int, val: int);

    /// Atomic exchange, sequentially consistent.
    pub fn atomic_xchg(dst: &mut int, src: int) -> int;
    /// Atomic exchange, acquire ordering.
    pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int;
    /// Atomic exchange, release ordering.
    pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int;

    /// Atomic addition, sequentially consistent.
    pub fn atomic_xadd(dst: &mut int, src: int) -> int;
    /// Atomic addition, acquire ordering.
    pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int;
    /// Atomic addition, release ordering.
    pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int;

    /// Atomic subtraction, sequentially consistent.
    pub fn atomic_xsub(dst: &mut int, src: int) -> int;
    /// Atomic subtraction, acquire ordering.
    pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int;
    /// Atomic subtraction, release ordering.
    pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int;

    /// The size of a type in bytes.
    ///
    /// This is the exact number of bytes in memory taken up by a
    /// value of the given type. In other words, a memset of this size
    /// would *exactly* overwrite a value. When laid out in vectors
    /// and structures there may be additional padding between
    /// elements.
    pub fn size_of<T>() -> uint;

    /// Move a value to a memory location containing a value.
    ///
    /// Drop glue is run on the destination, which must contain a
    /// valid Rust value.
    pub fn move_val<T>(dst: &mut T, src: T);

    /// Move a value to an uninitialized memory location.
    ///
    /// Drop glue is not run on the destination.
    pub fn move_val_init<T>(dst: &mut T, src: T);

    pub fn min_align_of<T>() -> uint;
    pub fn pref_align_of<T>() -> uint;

    /// Get a static pointer to a type descriptor.
    pub fn get_tydesc<T>() -> *();

    /// Create a value initialized to zero.
    ///
    /// `init` is unsafe because it returns a zeroed-out datum,
    /// which is unsafe unless T is POD. We don't have a POD
    /// kind yet. (See #4074).
    pub unsafe fn init<T>() -> T;

    /// Create an uninitialized value.
    pub unsafe fn uninit<T>() -> T;

    /// Move a value out of scope without running drop glue.
    ///
    /// `forget` is unsafe because the caller is responsible for
    /// ensuring the argument is deallocated already.
    pub unsafe fn forget<T>(_: T) -> ();
    pub fn transmute<T,U>(e: T) -> U;

    /// Returns `true` if a type requires drop glue.
    pub fn needs_drop<T>() -> bool;

    // XXX: intrinsic uses legacy modes and has reference to TyDesc
    // and TyVisitor which are in librustc
    //fn visit_tydesc(++td: *TyDesc, &&tv: TyVisitor) -> ();

    pub fn frame_address(f: &once fn(*u8));

    /// Get the address of the `__morestack` stack growth function.
    pub fn morestack_addr() -> *();

    /// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
    /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
    #[cfg(not(stage0))]
    pub fn memcpy32<T>(dst: *mut T, src: *T, count: u32);
    /// Equivalent to the `llvm.memcpy.p0i8.0i8.i64` intrinsic, with a size of
    /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
    #[cfg(not(stage0))]
    pub fn memcpy64<T>(dst: *mut T, src: *T, count: u64);

    /// Equivalent to the `llvm.memmove.p0i8.0i8.i32` intrinsic.
    #[cfg(stage0)]
    pub fn memmove32(dst: *mut u8, src: *u8, size: u32);
    /// Equivalent to the `llvm.memmove.p0i8.0i8.i64` intrinsic.
    #[cfg(stage0)]
    pub fn memmove64(dst: *mut u8, src: *u8, size: u64);

    /// Equivalent to the `llvm.memmove.p0i8.0i8.i32` intrinsic, with a size of
    /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
    #[cfg(not(stage0))]
    pub fn memmove32<T>(dst: *mut T, src: *T, count: u32);
    /// Equivalent to the `llvm.memmove.p0i8.0i8.i64` intrinsic, with a size of
    /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
    #[cfg(not(stage0))]
    pub fn memmove64<T>(dst: *mut T, src: *T, count: u64);

    pub fn sqrtf32(x: f32) -> f32;
    pub fn sqrtf64(x: f64) -> f64;

    pub fn powif32(a: f32, x: i32) -> f32;
    pub fn powif64(a: f64, x: i32) -> f64;

    // the following kill the stack canary without
    // `fixed_stack_segment`. This possibly only affects the f64
    // variants, but it's hard to be sure since it seems to only
    // occur with fairly specific arguments.
    #[fixed_stack_segment]
    pub fn sinf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn sinf64(x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn cosf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn cosf64(x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn powf32(a: f32, x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn powf64(a: f64, x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn expf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn expf64(x: f64) -> f64;

    pub fn exp2f32(x: f32) -> f32;
    pub fn exp2f64(x: f64) -> f64;

    pub fn logf32(x: f32) -> f32;
    pub fn logf64(x: f64) -> f64;

    pub fn log10f32(x: f32) -> f32;
    pub fn log10f64(x: f64) -> f64;

    pub fn log2f32(x: f32) -> f32;
    pub fn log2f64(x: f64) -> f64;

    pub fn fmaf32(a: f32, b: f32, c: f32) -> f32;
    pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;

    pub fn fabsf32(x: f32) -> f32;
    pub fn fabsf64(x: f64) -> f64;

    pub fn floorf32(x: f32) -> f32;
    pub fn floorf64(x: f64) -> f64;

    pub fn ceilf32(x: f32) -> f32;
    pub fn ceilf64(x: f64) -> f64;

    pub fn truncf32(x: f32) -> f32;
    pub fn truncf64(x: f64) -> f64;

    pub fn ctpop8(x: i8) -> i8;
    pub fn ctpop16(x: i16) -> i16;
    pub fn ctpop32(x: i32) -> i32;
    pub fn ctpop64(x: i64) -> i64;

    pub fn ctlz8(x: i8) -> i8;
    pub fn ctlz16(x: i16) -> i16;
    pub fn ctlz32(x: i32) -> i32;
    pub fn ctlz64(x: i64) -> i64;

    pub fn cttz8(x: i8) -> i8;
    pub fn cttz16(x: i16) -> i16;
    pub fn cttz32(x: i32) -> i32;
    pub fn cttz64(x: i64) -> i64;

    pub fn bswap16(x: i16) -> i16;
    pub fn bswap32(x: i32) -> i32;
    pub fn bswap64(x: i64) -> i64;
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 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 compiler code necessary to implement the #[deriving] extensions.

FIXME (#2810)--Hygiene. Search for "__" strings (in other files too).
We also assume "extra" is the standard library, and "std" is the core
library.

*/

use ast::{EnumDef, Ident, Item, Generics, StructDef};
use ast::{MetaItem, MetaList, MetaNameValue, MetaWord};
use ext::base::ExtCtxt;
use codemap::Span;

pub mod clone;
pub mod iter_bytes;
pub mod encodable;
pub mod decodable;
pub mod rand;
pub mod to_str;
pub mod zero;
pub mod default;
pub mod primitive;

#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/totaleq.rs"]
pub mod totaleq;
#[path="cmp/ord.rs"]
pub mod ord;
#[path="cmp/totalord.rs"]
pub mod totalord;

pub mod generic;

pub type ExpandDerivingStructDefFn<'a> = 'a |&ExtCtxt,
                                                   Span,
                                                   x: &StructDef,
                                                   Ident,
                                                   y: &Generics|
                                                   -> @Item;
pub type ExpandDerivingEnumDefFn<'a> = 'a |&ExtCtxt,
                                                 Span,
                                                 x: &EnumDef,
                                                 Ident,
                                                 y: &Generics|
                                                 -> @Item;

pub fn expand_meta_deriving(cx: &ExtCtxt,
                            _span: Span,
                            mitem: @MetaItem,
                            in_items: ~[@Item])
                         -> ~[@Item] {
    match mitem.node {
        MetaNameValue(_, ref l) => {
            cx.span_err(l.span, "unexpected value in `deriving`");
            in_items
        }
        MetaWord(_) | MetaList(_, []) => {
            cx.span_warn(mitem.span, "empty trait list in `deriving`");
            in_items
        }
        MetaList(_, ref titems) => {
            titems.rev_iter().fold(in_items, |in_items, &titem| {
                match titem.node {
                    MetaNameValue(ref tname, _) |
                    MetaList(ref tname, _) |
                    MetaWord(ref tname) => {
                        macro_rules! expand(($func:path) => ($func(cx, titem.span,
                                                                   titem, in_items)));
                        match tname.get() {
                            "Clone" => expand!(clone::expand_deriving_clone),
                            "DeepClone" => expand!(clone::expand_deriving_deep_clone),

                            "IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes),

                            "Encodable" => expand!(encodable::expand_deriving_encodable),
                            "Decodable" => expand!(decodable::expand_deriving_decodable),

                            "Eq" => expand!(eq::expand_deriving_eq),
                            "TotalEq" => expand!(totaleq::expand_deriving_totaleq),
                            "Ord" => expand!(ord::expand_deriving_ord),
                            "TotalOrd" => expand!(totalord::expand_deriving_totalord),

                            "Rand" => expand!(rand::expand_deriving_rand),

                            "ToStr" => expand!(to_str::expand_deriving_to_str),

                            "Zero" => expand!(zero::expand_deriving_zero),
                            "Default" => expand!(default::expand_deriving_default),

                            "FromPrimitive" => expand!(primitive::expand_deriving_from_primitive),

                            ref tname => {
                                cx.span_err(titem.span, format!("unknown \
                                    `deriving` trait: `{}`", *tname));
                                in_items
                            }
                        }
                    }
                }
            })
        }
    }
}
<commit_msg>syntax: remove some dead code.<commit_after>// Copyright 2012-2013 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 compiler code necessary to implement the #[deriving] extensions.

FIXME (#2810)--Hygiene. Search for "__" strings (in other files too).
We also assume "extra" is the standard library, and "std" is the core
library.

*/

use ast::{Item, MetaItem, MetaList, MetaNameValue, MetaWord};
use ext::base::ExtCtxt;
use codemap::Span;

pub mod clone;
pub mod iter_bytes;
pub mod encodable;
pub mod decodable;
pub mod rand;
pub mod to_str;
pub mod zero;
pub mod default;
pub mod primitive;

#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/totaleq.rs"]
pub mod totaleq;
#[path="cmp/ord.rs"]
pub mod ord;
#[path="cmp/totalord.rs"]
pub mod totalord;

pub mod generic;

pub fn expand_meta_deriving(cx: &ExtCtxt,
                            _span: Span,
                            mitem: @MetaItem,
                            in_items: ~[@Item])
                         -> ~[@Item] {
    match mitem.node {
        MetaNameValue(_, ref l) => {
            cx.span_err(l.span, "unexpected value in `deriving`");
            in_items
        }
        MetaWord(_) | MetaList(_, []) => {
            cx.span_warn(mitem.span, "empty trait list in `deriving`");
            in_items
        }
        MetaList(_, ref titems) => {
            titems.rev_iter().fold(in_items, |in_items, &titem| {
                match titem.node {
                    MetaNameValue(ref tname, _) |
                    MetaList(ref tname, _) |
                    MetaWord(ref tname) => {
                        macro_rules! expand(($func:path) => ($func(cx, titem.span,
                                                                   titem, in_items)));
                        match tname.get() {
                            "Clone" => expand!(clone::expand_deriving_clone),
                            "DeepClone" => expand!(clone::expand_deriving_deep_clone),

                            "IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes),

                            "Encodable" => expand!(encodable::expand_deriving_encodable),
                            "Decodable" => expand!(decodable::expand_deriving_decodable),

                            "Eq" => expand!(eq::expand_deriving_eq),
                            "TotalEq" => expand!(totaleq::expand_deriving_totaleq),
                            "Ord" => expand!(ord::expand_deriving_ord),
                            "TotalOrd" => expand!(totalord::expand_deriving_totalord),

                            "Rand" => expand!(rand::expand_deriving_rand),

                            "ToStr" => expand!(to_str::expand_deriving_to_str),

                            "Zero" => expand!(zero::expand_deriving_zero),
                            "Default" => expand!(default::expand_deriving_default),

                            "FromPrimitive" => expand!(primitive::expand_deriving_from_primitive),

                            ref tname => {
                                cx.span_err(titem.span, format!("unknown \
                                    `deriving` trait: `{}`", *tname));
                                in_items
                            }
                        }
                    }
                }
            })
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-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 compiler code necessary to implement the `#[derive]` extensions.

use syntax::ast::{MetaItem, MetaItemKind, self};
use syntax::attr::AttrMetaMethods;
use syntax::ext::base::{ExtCtxt, SyntaxEnv, Annotatable};
use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap::{self, Span};
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

macro_rules! path_std {
    ($($x:tt)*) => (
        ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) )
    )
}

pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod debug;
pub mod default;

#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/partial_ord.rs"]
pub mod partial_ord;
#[path="cmp/ord.rs"]
pub mod ord;

pub mod generic;

fn expand_derive(cx: &mut ExtCtxt,
                 span: Span,
                 mitem: &MetaItem,
                 annotatable: Annotatable)
                 -> Annotatable {
    debug!("expand_derive: span = {:?}", span);
    debug!("expand_derive: mitem = {:?}", mitem);
    debug!("expand_derive: annotatable input  = {:?}", annotatable);
    let annot = annotatable.map_item_or(|item| {
        item.map(|mut item| {
            if mitem.value_str().is_some() {
                cx.span_err(mitem.span, "unexpected value in `derive`");
            }

            let traits = mitem.meta_item_list().unwrap_or(&[]);
            if traits.is_empty() {
                cx.span_warn(mitem.span, "empty trait list in `derive`");
            }

            let mut found_partial_eq = false;
            let mut found_eq = false;

            for titem in traits.iter().rev() {
                let tname = match titem.node {
                    MetaItemKind::Word(ref tname) => tname,
                    _ => {
                        cx.span_err(titem.span, "malformed `derive` entry");
                        continue;
                    }
                };

                if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
                    feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
                                                   "custom_derive",
                                                   titem.span,
                                                   feature_gate::GateIssue::Language,
                                                   feature_gate::EXPLAIN_CUSTOM_DERIVE);
                    continue;
                }

                if &tname[..] == "Eq" {
                    found_eq = true;
                } else if &tname[..] == "PartialEq" {
                    found_partial_eq = true;
                }

                let span = Span {
                    expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                        call_site: titem.span,
                        callee: codemap::NameAndSpan {
                            format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
                            span: Some(titem.span),
                            allow_internal_unstable: true,
                        },
                    }), ..titem.span
                };

                // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
                item.attrs.push(cx.attribute(span, cx.meta_word(titem.span,
                    intern_and_get_ident(&format!("derive_{}", tname)))));
            }

            // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
            // `#[structural_match]` attribute.
            if found_partial_eq && found_eq {
                // This span is **very** sensitive and crucial to
                // getting the stability behavior we want. What we are
                // doing is marking `#[structural_match]` with the
                // span of the `#[deriving(...)]` attribute (the
                // entire attribute, not just the `PartialEq` or `Eq`
                // part), but with the current backtrace. The current
                // backtrace will contain a topmost entry that IS this
                // `#[deriving(...)]` attribute and with the
                // "allow-unstable" flag set to true.
                //
                // Note that we do NOT use the span of the `Eq`
                // text itself. You might think this is
                // equivalent, because the `Eq` appears within the
                // `#[deriving(Eq)]` attribute, and hence we would
                // inherit the "allows unstable" from the
                // backtrace.  But in fact this is not always the
                // case. The actual source text that led to
                // deriving can be `#[$attr]`, for example, where
                // `$attr == deriving(Eq)`. In that case, the
                // "#[structural_match]" would be considered to
                // originate not from the deriving call but from
                // text outside the deriving call, and hence would
                // be forbidden from using unstable
                // content.
                //
                // See tests src/run-pass/rfc1445 for
                // examples. --nmatsakis
                let span = Span { expn_id: cx.backtrace(), .. span };
                assert!(cx.parse_sess.codemap().span_allows_unstable(span));
                debug!("inserting structural_match with span {:?}", span);
                let structural_match = intern_and_get_ident("structural_match");
                item.attrs.push(cx.attribute(span,
                                             cx.meta_word(span,
                                                          structural_match)));
            }

            item
        })
    }, |a| {
        cx.span_err(span, "`derive` can only be applied to items");
        a
    });
    debug!("expand_derive: annotatable output = {:?}", annot);
    annot
}

macro_rules! derive_traits {
    ($( $name:expr => $func:path, )+) => {
        pub fn register_all(env: &mut SyntaxEnv) {
            // Define the #[derive_*] extensions.
            $({
                struct DeriveExtension;

                impl MultiItemDecorator for DeriveExtension {
                    fn expand(&self,
                              ecx: &mut ExtCtxt,
                              sp: Span,
                              mitem: &MetaItem,
                              annotatable: &Annotatable,
                              push: &mut FnMut(Annotatable)) {
                        if !ecx.parse_sess.codemap().span_allows_unstable(sp)
                            && !ecx.ecfg.features.unwrap().custom_derive {
                            // FIXME:
                            // https://github.com/rust-lang/rust/pull/32671#issuecomment-206245303
                            // This is just to avoid breakage with syntex.
                            // Remove that to spawn an error instead.
                            let cm = ecx.parse_sess.codemap();
                            let parent = cm.with_expn_info(ecx.backtrace(),
                                                           |info| info.unwrap().call_site.expn_id);
                            cm.with_expn_info(parent, |info| {
                                if info.is_some() {
                                    let mut w = ecx.parse_sess.span_diagnostic.struct_span_warn(
                                        sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE,
                                    );
                                    if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() {
                                        w.help(
                                            &format!("add #![feature(custom_derive)] to \
                                                      the crate attributes to enable")
                                        );
                                    }
                                    w.emit();
                                } else {
                                    feature_gate::emit_feature_err(
                                        &ecx.parse_sess.span_diagnostic,
                                        "custom_derive", sp, feature_gate::GateIssue::Language,
                                        feature_gate::EXPLAIN_DERIVE_UNDERSCORE
                                    );

                                    return;
                                }
                            })
                        }

                        warn_if_deprecated(ecx, sp, $name);
                        $func(ecx, sp, mitem, annotatable, push);
                    }
                }

                env.insert(intern(concat!("derive_", $name)),
                           MultiDecorator(Box::new(DeriveExtension)));
            })+

            env.insert(intern("derive"),
                       MultiModifier(Box::new(expand_derive)));
        }

        fn is_builtin_trait(name: &str) -> bool {
            match name {
                $( $name )|+ => true,
                _ => false,
            }
        }
    }
}

derive_traits! {
    "Clone" => clone::expand_deriving_clone,

    "Hash" => hash::expand_deriving_hash,

    "RustcEncodable" => encodable::expand_deriving_rustc_encodable,

    "RustcDecodable" => decodable::expand_deriving_rustc_decodable,

    "PartialEq" => partial_eq::expand_deriving_partial_eq,
    "Eq" => eq::expand_deriving_eq,
    "PartialOrd" => partial_ord::expand_deriving_partial_ord,
    "Ord" => ord::expand_deriving_ord,

    "Debug" => debug::expand_deriving_debug,

    "Default" => default::expand_deriving_default,

    "Send" => bounds::expand_deriving_unsafe_bound,
    "Sync" => bounds::expand_deriving_unsafe_bound,
    "Copy" => bounds::expand_deriving_copy,

    // deprecated
    "Encodable" => encodable::expand_deriving_encodable,
    "Decodable" => decodable::expand_deriving_decodable,
}

#[inline] // because `name` is a compile-time constant
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
    if let Some(replacement) = match name {
        "Encodable" => Some("RustcEncodable"),
        "Decodable" => Some("RustcDecodable"),
        _ => None,
    } {
        ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})",
                                   name, replacement));
    }
}

/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
    let mut typaram = String::from(base);
    if let Annotatable::Item(ref item) = *item {
        match item.node {
            ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
                ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {

                for ty in ty_params.iter() {
                    typaram.push_str(&ty.ident.name.as_str());
                }
            }

            _ => {}
        }
    }

    typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
                  span: Span,
                  intrinsic: &str,
                  args: Vec<P<ast::Expr>>) -> P<ast::Expr> {
    let path = cx.std_path(&["intrinsics", intrinsic]);
    let call = cx.expr_call_global(span, path, args);

    cx.expr_block(P(ast::Block {
        stmts: vec![],
        expr: Some(call),
        id: ast::DUMMY_NODE_ID,
        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
        span: span }))
}

<commit_msg>Use the span of `#[derive_Eq]` for `#[structural_match]`<commit_after>// Copyright 2012-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 compiler code necessary to implement the `#[derive]` extensions.

use syntax::ast::{MetaItem, MetaItemKind, self};
use syntax::attr::AttrMetaMethods;
use syntax::ext::base::{ExtCtxt, SyntaxEnv, Annotatable};
use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap::{self, Span};
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

macro_rules! path_std {
    ($($x:tt)*) => (
        ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) )
    )
}

pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod debug;
pub mod default;

#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/partial_ord.rs"]
pub mod partial_ord;
#[path="cmp/ord.rs"]
pub mod ord;

pub mod generic;

fn expand_derive(cx: &mut ExtCtxt,
                 span: Span,
                 mitem: &MetaItem,
                 annotatable: Annotatable)
                 -> Annotatable {
    debug!("expand_derive: span = {:?}", span);
    debug!("expand_derive: mitem = {:?}", mitem);
    debug!("expand_derive: annotatable input  = {:?}", annotatable);
    let annot = annotatable.map_item_or(|item| {
        item.map(|mut item| {
            if mitem.value_str().is_some() {
                cx.span_err(mitem.span, "unexpected value in `derive`");
            }

            let traits = mitem.meta_item_list().unwrap_or(&[]);
            if traits.is_empty() {
                cx.span_warn(mitem.span, "empty trait list in `derive`");
            }

            let mut found_partial_eq = false;
            let mut eq_span = None;

            for titem in traits.iter().rev() {
                let tname = match titem.node {
                    MetaItemKind::Word(ref tname) => tname,
                    _ => {
                        cx.span_err(titem.span, "malformed `derive` entry");
                        continue;
                    }
                };

                if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
                    feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
                                                   "custom_derive",
                                                   titem.span,
                                                   feature_gate::GateIssue::Language,
                                                   feature_gate::EXPLAIN_CUSTOM_DERIVE);
                    continue;
                }

                let span = Span {
                    expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                        call_site: titem.span,
                        callee: codemap::NameAndSpan {
                            format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
                            span: Some(titem.span),
                            allow_internal_unstable: true,
                        },
                    }), ..titem.span
                };

                if &tname[..] == "Eq" {
                    eq_span = Some(span);
                } else if &tname[..] == "PartialEq" {
                    found_partial_eq = true;
                }

                // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
                item.attrs.push(cx.attribute(span, cx.meta_word(titem.span,
                    intern_and_get_ident(&format!("derive_{}", tname)))));
            }

            // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
            // `#[structural_match]` attribute.
            if let Some(eq_span) = eq_span {
                if found_partial_eq {
                    let structural_match = intern_and_get_ident("structural_match");
                    item.attrs.push(cx.attribute(eq_span,
                                                 cx.meta_word(eq_span,
                                                              structural_match)));
                }
            }

            item
        })
    }, |a| {
        cx.span_err(span, "`derive` can only be applied to items");
        a
    });
    debug!("expand_derive: annotatable output = {:?}", annot);
    annot
}

macro_rules! derive_traits {
    ($( $name:expr => $func:path, )+) => {
        pub fn register_all(env: &mut SyntaxEnv) {
            // Define the #[derive_*] extensions.
            $({
                struct DeriveExtension;

                impl MultiItemDecorator for DeriveExtension {
                    fn expand(&self,
                              ecx: &mut ExtCtxt,
                              sp: Span,
                              mitem: &MetaItem,
                              annotatable: &Annotatable,
                              push: &mut FnMut(Annotatable)) {
                        if !ecx.parse_sess.codemap().span_allows_unstable(sp)
                            && !ecx.ecfg.features.unwrap().custom_derive {
                            // FIXME:
                            // https://github.com/rust-lang/rust/pull/32671#issuecomment-206245303
                            // This is just to avoid breakage with syntex.
                            // Remove that to spawn an error instead.
                            let cm = ecx.parse_sess.codemap();
                            let parent = cm.with_expn_info(ecx.backtrace(),
                                                           |info| info.unwrap().call_site.expn_id);
                            cm.with_expn_info(parent, |info| {
                                if info.is_some() {
                                    let mut w = ecx.parse_sess.span_diagnostic.struct_span_warn(
                                        sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE,
                                    );
                                    if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() {
                                        w.help(
                                            &format!("add #![feature(custom_derive)] to \
                                                      the crate attributes to enable")
                                        );
                                    }
                                    w.emit();
                                } else {
                                    feature_gate::emit_feature_err(
                                        &ecx.parse_sess.span_diagnostic,
                                        "custom_derive", sp, feature_gate::GateIssue::Language,
                                        feature_gate::EXPLAIN_DERIVE_UNDERSCORE
                                    );

                                    return;
                                }
                            })
                        }

                        warn_if_deprecated(ecx, sp, $name);
                        $func(ecx, sp, mitem, annotatable, push);
                    }
                }

                env.insert(intern(concat!("derive_", $name)),
                           MultiDecorator(Box::new(DeriveExtension)));
            })+

            env.insert(intern("derive"),
                       MultiModifier(Box::new(expand_derive)));
        }

        fn is_builtin_trait(name: &str) -> bool {
            match name {
                $( $name )|+ => true,
                _ => false,
            }
        }
    }
}

derive_traits! {
    "Clone" => clone::expand_deriving_clone,

    "Hash" => hash::expand_deriving_hash,

    "RustcEncodable" => encodable::expand_deriving_rustc_encodable,

    "RustcDecodable" => decodable::expand_deriving_rustc_decodable,

    "PartialEq" => partial_eq::expand_deriving_partial_eq,
    "Eq" => eq::expand_deriving_eq,
    "PartialOrd" => partial_ord::expand_deriving_partial_ord,
    "Ord" => ord::expand_deriving_ord,

    "Debug" => debug::expand_deriving_debug,

    "Default" => default::expand_deriving_default,

    "Send" => bounds::expand_deriving_unsafe_bound,
    "Sync" => bounds::expand_deriving_unsafe_bound,
    "Copy" => bounds::expand_deriving_copy,

    // deprecated
    "Encodable" => encodable::expand_deriving_encodable,
    "Decodable" => decodable::expand_deriving_decodable,
}

#[inline] // because `name` is a compile-time constant
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
    if let Some(replacement) = match name {
        "Encodable" => Some("RustcEncodable"),
        "Decodable" => Some("RustcDecodable"),
        _ => None,
    } {
        ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})",
                                   name, replacement));
    }
}

/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
    let mut typaram = String::from(base);
    if let Annotatable::Item(ref item) = *item {
        match item.node {
            ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
                ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {

                for ty in ty_params.iter() {
                    typaram.push_str(&ty.ident.name.as_str());
                }
            }

            _ => {}
        }
    }

    typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
                  span: Span,
                  intrinsic: &str,
                  args: Vec<P<ast::Expr>>) -> P<ast::Expr> {
    let path = cx.std_path(&["intrinsics", intrinsic]);
    let call = cx.expr_call_global(span, path, args);

    cx.expr_block(P(ast::Block {
        stmts: vec![],
        expr: Some(call),
        id: ast::DUMMY_NODE_ID,
        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
        span: span }))
}

<|endoftext|>


<commit_before>// use std::slice;
use std::path::{Path, PathBuf};
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard};
use std::cmp;

use rex::filesystem::FileSystem;

use super::bytes;

lazy_static! {
    pub static ref FILES: Mutex<HashMap<PathBuf, Arc<Mutex<Vec<u8>>>>> = Mutex::new(HashMap::new());
}

pub struct MockFile {
    pub locked_vec: Arc<Mutex<Vec<u8>>>,
    pub pos: u64,
}

impl MockFile {
    fn new(vec: Arc<Mutex<Vec<u8>>>) -> MockFile {
        MockFile {
            locked_vec: vec,
            pos: 0,
        }
    }
}

impl Read for MockFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let vec = self.locked_vec.lock().unwrap();
        let len = cmp::min(vec.len() - self.pos as usize, buf.len());
        let src_slice = &vec[self.pos as usize..(self.pos as usize + len)];
        {
            let mut dest_slice = &mut buf[..len];

            assert_eq!(src_slice.len(), dest_slice.len());

            bytes::copy_memory(src_slice, dest_slice);
        }
        self.pos += len as u64;

        Ok(len)
    }
}

impl Write for MockFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut vec = self.locked_vec.lock().unwrap();

        // Since we do not support seek, this is pretty simple
        vec.extend(buf.iter());

        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

pub struct MockFileSystem;

impl FileSystem for MockFileSystem {
    type FSRead = MockFile;
    type FSWrite = MockFile;

    fn open<P: AsRef<Path>>(path: P) -> io::Result<Self::FSRead> {
        FILES.lock().unwrap().get(path.as_ref()).ok_or(io::Error::new(io::ErrorKind::NotFound, "File not found!")).map(|file|
            MockFile::new(file.clone())
        )
    }

    fn save<P: AsRef<Path>>(path: P) -> io::Result<Self::FSWrite> {
        let file = Arc::new(Mutex::new(Vec::new()));
        if let Entry::Vacant(entry) = FILES.lock().unwrap().entry(path.as_ref().into()) {
            entry.insert(file.clone());
            Ok(MockFile::new(file))
        } else {
            Err(io::Error::new(io::ErrorKind::AlreadyExists, "File alredy exists!"))
        }
    }
}

impl MockFileSystem {
    pub fn reset() {
        FILES.lock().unwrap().clear();
    }

    pub fn get_inner<'a, P: AsRef<Path>>(path: P) -> Vec<u8> {
        // This function is very ugly, in general we would like to "unwrap" the file from the
        // mock filesystem. Sadly, there doesn't seem to be a better way.
        let f = FILES.lock().unwrap().remove(path.as_ref()).unwrap();
        let a = Arc::try_unwrap(f).unwrap();
        let m = a.lock().unwrap();
        let v = m.clone();
        v
    }

    pub fn put<'a, P: AsRef<Path>>(path: P, v: Vec<u8>) {
        FILES.lock().unwrap().insert(path.as_ref().into(), Arc::new(Mutex::new(v)));
    }
}
<commit_msg>Change the mock file to use a cursor instead of our own implementation<commit_after>// use std::slice;
use std::path::{Path, PathBuf};
use std::io;
use std::io::{Cursor, Read, Write};
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard};
use std::cmp;

use rex::filesystem::FileSystem;

use super::bytes;

lazy_static! {
    pub static ref FILES: Mutex<HashMap<PathBuf, Arc<Mutex<Cursor<Vec<u8>>>>>> = Mutex::new(HashMap::new());
}

pub struct MockFile(Arc<Mutex<Cursor<Vec<u8>>>>);

impl MockFile {
    fn new(vec: Arc<Mutex<Cursor<Vec<u8>>>>) -> MockFile {
        MockFile(vec)
    }
}

impl Read for MockFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.read(buf)
    }
}

impl Write for MockFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        let mut vec = self.0.lock().unwrap();
        vec.flush()
    }
}

pub struct MockFileSystem;

impl FileSystem for MockFileSystem {
    type FSRead = MockFile;
    type FSWrite = MockFile;

    fn open<P: AsRef<Path>>(path: P) -> io::Result<Self::FSRead> {
        FILES.lock().unwrap().get(path.as_ref()).ok_or(io::Error::new(io::ErrorKind::NotFound, "File not found!")).map(|file|
            MockFile::new(file.clone())
        )
    }

    fn save<P: AsRef<Path>>(path: P) -> io::Result<Self::FSWrite> {
        let file = Arc::new(Mutex::new(Cursor::new(Vec::new())));
        if let Entry::Vacant(entry) = FILES.lock().unwrap().entry(path.as_ref().into()) {
            entry.insert(file.clone());
            Ok(MockFile::new(file))
        } else {
            Err(io::Error::new(io::ErrorKind::AlreadyExists, "File alredy exists!"))
        }
    }
}

impl MockFileSystem {
    pub fn reset() {
        FILES.lock().unwrap().clear();
    }

    pub fn get_inner<'a, P: AsRef<Path>>(path: P) -> Vec<u8> {
        // This function is very ugly, in general we would like to "unwrap" the file from the
        // mock filesystem. Sadly, there doesn't seem to be a better way.
        let f = FILES.lock().unwrap().remove(path.as_ref()).unwrap();
        let a = Arc::try_unwrap(f).unwrap();
        let m = a.lock().unwrap();
        let v = m.clone();
        v.into_inner()
    }

    pub fn put<'a, P: AsRef<Path>>(path: P, v: Vec<u8>) {
        FILES.lock().unwrap().insert(path.as_ref().into(), Arc::new(Mutex::new(Cursor::new(v))));
    }
}
<|endoftext|>


<commit_before>#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

// #![ feature( trace_macros ) ]
#![ feature( type_name_of_val ) ]

use type_constructor as TheModule;
#[ allow( unused_imports ) ]
use test_tools::*;

#[ path = "./inc.rs" ]
mod inc;

// zzz : move to inc after implementing macro to check presence of a dependency
#[ cfg( feature = "use_std" ) ]
#[ test_tools::rustversion::nightly ]
#[ test ]
fn trybuild_tests()
{
  use test_tools::trybuild;
  println!( "current_dir : {:?}", std::env::current_dir().unwrap() );
  #[ allow( unused_variables ) ]
  let t = trybuild::TestCases::new();
  #[ cfg( any( feature = "make", feature = "dt_make" ) ) ]
  t.compile_fail( "../../../rust/test/dt/type_constructor/dynamic/make/*.rs" );

  #[ cfg( all( any( feature = "use_std", feature = "use_alloc" ), feature = "many" ) ) ]
  t.compile_fail( "../../../rust/test/dt/type_constructor/dynamic/types_many_yes/*.rs" );

  #[ cfg( any( not( any( feature = "use_std", feature = "use_alloc" ) ), not( feature = "many" ) ) ) ]
  t.compile_fail( "../../../rust/test/dt/type_constructor/dynamic/types_many_no/*.rs" );
}
<commit_msg>Fix tests of module `type_constructor`, disable unstable feature<commit_after>#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

// #![ feature( trace_macros ) ]
// #![ feature( type_name_of_val ) ]

use type_constructor as TheModule;
#[ allow( unused_imports ) ]
use test_tools::*;

#[ path = "./inc.rs" ]
mod inc;

// zzz : move to inc after implementing macro to check presence of a dependency
#[ cfg( feature = "use_std" ) ]
#[ test_tools::rustversion::nightly ]
#[ test ]
fn trybuild_tests()
{
  use test_tools::trybuild;
  println!( "current_dir : {:?}", std::env::current_dir().unwrap() );
  #[ allow( unused_variables ) ]
  let t = trybuild::TestCases::new();
  #[ cfg( any( feature = "make", feature = "dt_make" ) ) ]
  t.compile_fail( "../../../rust/test/dt/type_constructor/dynamic/make/*.rs" );

  #[ cfg( all( any( feature = "use_std", feature = "use_alloc" ), feature = "many" ) ) ]
  t.compile_fail( "../../../rust/test/dt/type_constructor/dynamic/types_many_yes/*.rs" );

  #[ cfg( any( not( any( feature = "use_std", feature = "use_alloc" ) ), not( feature = "many" ) ) ) ]
  t.compile_fail( "../../../rust/test/dt/type_constructor/dynamic/types_many_no/*.rs" );
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::io::fs::PathExtensions;
use std::io::{fs, USER_RWX, File};
use std::str;
use std::sync::Mutex;

use core::{Package, Target, PackageId, PackageSet};
use util::{CargoResult, CargoError, human};
use util::{internal, ChainError, Require};

use super::job::Work;
use super::{fingerprint, process, Kind, Context, Platform};
use util::Freshness;

/// Contains the parsed output of a custom build script.
#[deriving(Clone)]
pub struct BuildOutput {
    /// Paths to pass to rustc with the `-L` flag
    pub library_paths: Vec<Path>,
    /// Names and link kinds of libraries, suitable for the `-l` flag
    pub library_links: Vec<String>,
    /// Metadata to pass to the immediate dependencies
    pub metadata: Vec<(String, String)>,
}

pub struct BuildState {
    pub outputs: Mutex<HashMap<(PackageId, Kind), BuildOutput>>,
}

/// Prepares a `Work` that executes the target as a custom build script.
///
/// The `req` given is the requirement which this run of the build script will
/// prepare work for. If the requirement is specified as both the target and the
/// host platforms it is assumed that the two are equal and the build script is
/// only run once (not twice).
pub fn prepare(pkg: &Package, target: &Target, req: Platform,
               cx: &mut Context) -> CargoResult<(Work, Work, Freshness)> {
    let kind = match req { Platform::Plugin => Kind::Host, _ => Kind::Target, };
    let (script_output, build_output) = {
        (cx.layout(pkg, Kind::Host).build(pkg),
         cx.layout(pkg, Kind::Target).build_out(pkg))
    };

    // Building the command to execute
    let to_exec = try!(cx.target_filenames(target))[0].clone();
    let to_exec = script_output.join(to_exec);

    // Start preparing the process to execute, starting out with some
    // environment variables.
    let profile = target.get_profile();
    let mut p = try!(super::process(to_exec, pkg, target, cx))
                     .env("OUT_DIR", Some(&build_output))
                     .env("CARGO_MANIFEST_DIR", Some(pkg.get_manifest_path()
                                                        .dir_path()
                                                        .display().to_string()))
                     .env("NUM_JOBS", Some(cx.config.jobs().to_string()))
                     .env("TARGET", Some(match kind {
                         Kind::Host => cx.config.rustc_host(),
                         Kind::Target => cx.target_triple(),
                     }))
                     .env("DEBUG", Some(profile.get_debug().to_string()))
                     .env("OPT_LEVEL", Some(profile.get_opt_level().to_string()))
                     .env("PROFILE", Some(profile.get_env()));

    // Be sure to pass along all enabled features for this package, this is the
    // last piece of statically known information that we have.
    match cx.resolve.features(pkg.get_package_id()) {
        Some(features) => {
            for feat in features.iter() {
                p = p.env(format!("CARGO_FEATURE_{}",
                                  super::envify(feat.as_slice())).as_slice(),
                          Some("1"));
            }
        }
        None => {}
    }

    // Gather the set of native dependencies that this package has along with
    // some other variables to close over.
    //
    // This information will be used at build-time later on to figure out which
    // sorts of variables need to be discovered at that time.
    let lib_deps = {
        let non_build_target = pkg.get_targets().iter().find(|t| {
            !t.get_profile().is_custom_build()
        }).unwrap();
        cx.dep_targets(pkg, non_build_target).iter().filter_map(|&(pkg, _)| {
            pkg.get_manifest().get_links().map(|links| {
                (links.to_string(), pkg.get_package_id().clone())
            })
        }).collect::<Vec<_>>()
    };
    let pkg_name = pkg.to_string();
    let build_state = cx.build_state.clone();
    let id = pkg.get_package_id().clone();
    let all = (id.clone(), pkg_name.clone(), build_state.clone(),
               build_output.clone());

    try!(fs::mkdir_recursive(&cx.layout(pkg, Kind::Target).build(pkg), USER_RWX));
    try!(fs::mkdir_recursive(&cx.layout(pkg, Kind::Host).build(pkg), USER_RWX));

    // Prepare the unit of "dirty work" which will actually run the custom build
    // command.
    //
    // Note that this has to do some extra work just before running the command
    // to determine extra environment variables and such.
    let work = proc(desc_tx: Sender<String>) {
        // Make sure that OUT_DIR exists.
        //
        // If we have an old build directory, then just move it into place,
        // otherwise create it!
        if !build_output.exists() {
            try!(fs::mkdir(&build_output, USER_RWX).chain_error(|| {
                internal("failed to create script output directory for \
                          build command")
            }));
        }

        // For all our native lib dependencies, pick up their metadata to pass
        // along to this custom build command.
        let mut p = p;
        {
            let build_state = build_state.outputs.lock();
            for &(ref name, ref id) in lib_deps.iter() {
                let data = &build_state[(id.clone(), kind)].metadata;
                for &(ref key, ref value) in data.iter() {
                    p = p.env(format!("DEP_{}_{}",
                                      super::envify(name.as_slice()),
                                      super::envify(key.as_slice())).as_slice(),
                              Some(value.as_slice()));
                }
            }
        }

        // And now finally, run the build command itself!
        desc_tx.send_opt(p.to_string()).ok();
        let output = try!(p.exec_with_output().map_err(|mut e| {
            e.msg = format!("Failed to run custom build command for `{}`\n{}",
                            pkg_name, e.msg);
            e.concrete().mark_human()
        }));

        // After the build command has finished running, we need to be sure to
        // remember all of its output so we can later discover precisely what it
        // was, even if we don't run the build command again (due to freshness).
        //
        // This is also the location where we provide feedback into the build
        // state informing what variables were discovered via our script as
        // well.
        let output = try!(str::from_utf8(output.output.as_slice()).require(|| {
            human("build script output was not valid utf-8")
        }));
        let parsed_output = try!(BuildOutput::parse(output, pkg_name.as_slice()));
        build_state.insert(id, req, parsed_output);

        try!(File::create(&build_output.dir_path().join("output"))
                  .write_str(output).map_err(|e| {
            human(format!("failed to write output of custom build command: {}",
                          e))
        }));

        Ok(())
    };

    // Now that we've prepared our work-to-do, we need to prepare the fresh work
    // itself to run when we actually end up just discarding what we calculated
    // above.
    //
    // Note that the freshness calculation here is the build_cmd freshness, not
    // target specific freshness. This is because we don't actually know what
    // the inputs are to this command!
    //
    // Also note that a fresh build command needs to
    let (freshness, dirty, fresh) =
            try!(fingerprint::prepare_build_cmd(cx, pkg, Some(target)));
    let dirty = proc(tx: Sender<String>) { try!(work(tx.clone())); dirty(tx) };
    let fresh = proc(tx) {
        let (id, pkg_name, build_state, build_output) = all;
        let new_loc = build_output.dir_path().join("output");
        let mut f = try!(File::open(&new_loc).map_err(|e| {
            human(format!("failed to read cached build command output: {}", e))
        }));
        let contents = try!(f.read_to_string());
        let output = try!(BuildOutput::parse(contents.as_slice(),
                                             pkg_name.as_slice()));
        build_state.insert(id, req, output);

        fresh(tx)
    };

    Ok((dirty, fresh, freshness))
}

impl BuildState {
    pub fn new(config: super::BuildConfig,
               packages: &PackageSet) -> BuildState {
        let mut sources = HashMap::new();
        for package in packages.iter() {
            match package.get_manifest().get_links() {
                Some(links) => {
                    sources.insert(links.to_string(),
                                   package.get_package_id().clone());
                }
                None => {}
            }
        }
        let mut outputs = HashMap::new();
        let i1 = config.host.overrides.into_iter().map(|p| (p, Kind::Host));
        let i2 = config.target.overrides.into_iter().map(|p| (p, Kind::Target));
        for ((name, output), kind) in i1.chain(i2) {
            match sources.get(&name) {
                Some(id) => { outputs.insert((id.clone(), kind), output); }

                // If no package is using the library named `name`, then this is
                // just an override that we ignore.
                None => {}
            }
        }
        BuildState { outputs: Mutex::new(outputs) }
    }

    fn insert(&self, id: PackageId, req: Platform,
              output: BuildOutput) {
        let mut outputs = self.outputs.lock();
        match req {
            Platform::Target => { outputs.insert((id, Kind::Target), output); }
            Platform::Plugin => { outputs.insert((id, Kind::Host), output); }

            // If this build output was for both the host and target platforms,
            // we need to insert it at both places.
            Platform::PluginAndTarget => {
                outputs.insert((id.clone(), Kind::Host), output.clone());
                outputs.insert((id, Kind::Target), output);
            }
        }
    }
}

impl BuildOutput {
    // Parses the output of a script.
    // The `pkg_name` is used for error messages.
    pub fn parse(input: &str, pkg_name: &str) -> CargoResult<BuildOutput> {
        let mut library_paths = Vec::new();
        let mut library_links = Vec::new();
        let mut metadata = Vec::new();
        let whence = format!("build script of `{}`", pkg_name);

        for line in input.lines() {
            let mut iter = line.splitn(1, |c: char| c == ':');
            if iter.next() != Some("cargo") {
                // skip this line since it doesn't start with "cargo:"
                continue;
            }
            let data = match iter.next() {
                Some(val) => val,
                None => continue
            };

            // getting the `key=value` part of the line
            let mut iter = data.splitn(1, |c: char| c == '=');
            let key = iter.next();
            let value = iter.next();
            let (key, value) = match (key, value) {
                (Some(a), Some(b)) => (a, b.trim_right()),
                // line started with `cargo:` but didn't match `key=value`
                _ => return Err(human(format!("Wrong output in {}: `{}`",
                                              whence, line)))
            };

            if key == "rustc-flags" {
                let whence = whence.as_slice();
                let (libs, links) = try!(
                    BuildOutput::parse_rustc_flags(value, whence)
                );
                library_links.extend(links.into_iter());
                library_paths.extend(libs.into_iter());
            } else {
                metadata.push((key.to_string(), value.to_string()))
            }
        }

        Ok(BuildOutput {
            library_paths: library_paths,
            library_links: library_links,
            metadata: metadata,
        })
    }

    pub fn parse_rustc_flags(value: &str, whence: &str)
                             -> CargoResult<(Vec<Path>, Vec<String>)> {
        // TODO: some arguments (like paths) may contain spaces
        let value = value.trim();
        let mut flags_iter = value.words();
        let (mut library_links, mut library_paths) = (Vec::new(), Vec::new());
        loop {
            let flag = match flags_iter.next() {
                Some(f) => f,
                None => break
            };
            if flag != "-l" && flag != "-L" {
                return Err(human(format!("Only `-l` and `-L` flags are allowed \
                                         in {}: `{}`",
                                         whence, value)))
            }
            let value = match flags_iter.next() {
                Some(v) => v,
                None => return Err(human(format!("Flag in rustc-flags has no value\
                                                  in {}: `{}`",
                                                  whence, value)))
            };
            match flag {
                "-l" => library_links.push(value.to_string()),
                "-L" => library_paths.push(Path::new(value)),

                // was already checked above
                _ => return Err(human("only -l and -L flags are allowed"))
            };
        }
        Ok((library_paths, library_links))
    }
}

impl fmt::Show for BuildOutput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BuildOutput {{ paths: [..], libs: {}, metadata: {} }}",
               self.library_links, self.metadata)
    }
}
<commit_msg>Fix typo in build script error<commit_after>use std::collections::HashMap;
use std::fmt;
use std::io::fs::PathExtensions;
use std::io::{fs, USER_RWX, File};
use std::str;
use std::sync::Mutex;

use core::{Package, Target, PackageId, PackageSet};
use util::{CargoResult, CargoError, human};
use util::{internal, ChainError, Require};

use super::job::Work;
use super::{fingerprint, process, Kind, Context, Platform};
use util::Freshness;

/// Contains the parsed output of a custom build script.
#[deriving(Clone)]
pub struct BuildOutput {
    /// Paths to pass to rustc with the `-L` flag
    pub library_paths: Vec<Path>,
    /// Names and link kinds of libraries, suitable for the `-l` flag
    pub library_links: Vec<String>,
    /// Metadata to pass to the immediate dependencies
    pub metadata: Vec<(String, String)>,
}

pub struct BuildState {
    pub outputs: Mutex<HashMap<(PackageId, Kind), BuildOutput>>,
}

/// Prepares a `Work` that executes the target as a custom build script.
///
/// The `req` given is the requirement which this run of the build script will
/// prepare work for. If the requirement is specified as both the target and the
/// host platforms it is assumed that the two are equal and the build script is
/// only run once (not twice).
pub fn prepare(pkg: &Package, target: &Target, req: Platform,
               cx: &mut Context) -> CargoResult<(Work, Work, Freshness)> {
    let kind = match req { Platform::Plugin => Kind::Host, _ => Kind::Target, };
    let (script_output, build_output) = {
        (cx.layout(pkg, Kind::Host).build(pkg),
         cx.layout(pkg, Kind::Target).build_out(pkg))
    };

    // Building the command to execute
    let to_exec = try!(cx.target_filenames(target))[0].clone();
    let to_exec = script_output.join(to_exec);

    // Start preparing the process to execute, starting out with some
    // environment variables.
    let profile = target.get_profile();
    let mut p = try!(super::process(to_exec, pkg, target, cx))
                     .env("OUT_DIR", Some(&build_output))
                     .env("CARGO_MANIFEST_DIR", Some(pkg.get_manifest_path()
                                                        .dir_path()
                                                        .display().to_string()))
                     .env("NUM_JOBS", Some(cx.config.jobs().to_string()))
                     .env("TARGET", Some(match kind {
                         Kind::Host => cx.config.rustc_host(),
                         Kind::Target => cx.target_triple(),
                     }))
                     .env("DEBUG", Some(profile.get_debug().to_string()))
                     .env("OPT_LEVEL", Some(profile.get_opt_level().to_string()))
                     .env("PROFILE", Some(profile.get_env()));

    // Be sure to pass along all enabled features for this package, this is the
    // last piece of statically known information that we have.
    match cx.resolve.features(pkg.get_package_id()) {
        Some(features) => {
            for feat in features.iter() {
                p = p.env(format!("CARGO_FEATURE_{}",
                                  super::envify(feat.as_slice())).as_slice(),
                          Some("1"));
            }
        }
        None => {}
    }

    // Gather the set of native dependencies that this package has along with
    // some other variables to close over.
    //
    // This information will be used at build-time later on to figure out which
    // sorts of variables need to be discovered at that time.
    let lib_deps = {
        let non_build_target = pkg.get_targets().iter().find(|t| {
            !t.get_profile().is_custom_build()
        }).unwrap();
        cx.dep_targets(pkg, non_build_target).iter().filter_map(|&(pkg, _)| {
            pkg.get_manifest().get_links().map(|links| {
                (links.to_string(), pkg.get_package_id().clone())
            })
        }).collect::<Vec<_>>()
    };
    let pkg_name = pkg.to_string();
    let build_state = cx.build_state.clone();
    let id = pkg.get_package_id().clone();
    let all = (id.clone(), pkg_name.clone(), build_state.clone(),
               build_output.clone());

    try!(fs::mkdir_recursive(&cx.layout(pkg, Kind::Target).build(pkg), USER_RWX));
    try!(fs::mkdir_recursive(&cx.layout(pkg, Kind::Host).build(pkg), USER_RWX));

    // Prepare the unit of "dirty work" which will actually run the custom build
    // command.
    //
    // Note that this has to do some extra work just before running the command
    // to determine extra environment variables and such.
    let work = proc(desc_tx: Sender<String>) {
        // Make sure that OUT_DIR exists.
        //
        // If we have an old build directory, then just move it into place,
        // otherwise create it!
        if !build_output.exists() {
            try!(fs::mkdir(&build_output, USER_RWX).chain_error(|| {
                internal("failed to create script output directory for \
                          build command")
            }));
        }

        // For all our native lib dependencies, pick up their metadata to pass
        // along to this custom build command.
        let mut p = p;
        {
            let build_state = build_state.outputs.lock();
            for &(ref name, ref id) in lib_deps.iter() {
                let data = &build_state[(id.clone(), kind)].metadata;
                for &(ref key, ref value) in data.iter() {
                    p = p.env(format!("DEP_{}_{}",
                                      super::envify(name.as_slice()),
                                      super::envify(key.as_slice())).as_slice(),
                              Some(value.as_slice()));
                }
            }
        }

        // And now finally, run the build command itself!
        desc_tx.send_opt(p.to_string()).ok();
        let output = try!(p.exec_with_output().map_err(|mut e| {
            e.msg = format!("Failed to run custom build command for `{}`\n{}",
                            pkg_name, e.msg);
            e.concrete().mark_human()
        }));

        // After the build command has finished running, we need to be sure to
        // remember all of its output so we can later discover precisely what it
        // was, even if we don't run the build command again (due to freshness).
        //
        // This is also the location where we provide feedback into the build
        // state informing what variables were discovered via our script as
        // well.
        let output = try!(str::from_utf8(output.output.as_slice()).require(|| {
            human("build script output was not valid utf-8")
        }));
        let parsed_output = try!(BuildOutput::parse(output, pkg_name.as_slice()));
        build_state.insert(id, req, parsed_output);

        try!(File::create(&build_output.dir_path().join("output"))
                  .write_str(output).map_err(|e| {
            human(format!("failed to write output of custom build command: {}",
                          e))
        }));

        Ok(())
    };

    // Now that we've prepared our work-to-do, we need to prepare the fresh work
    // itself to run when we actually end up just discarding what we calculated
    // above.
    //
    // Note that the freshness calculation here is the build_cmd freshness, not
    // target specific freshness. This is because we don't actually know what
    // the inputs are to this command!
    //
    // Also note that a fresh build command needs to
    let (freshness, dirty, fresh) =
            try!(fingerprint::prepare_build_cmd(cx, pkg, Some(target)));
    let dirty = proc(tx: Sender<String>) { try!(work(tx.clone())); dirty(tx) };
    let fresh = proc(tx) {
        let (id, pkg_name, build_state, build_output) = all;
        let new_loc = build_output.dir_path().join("output");
        let mut f = try!(File::open(&new_loc).map_err(|e| {
            human(format!("failed to read cached build command output: {}", e))
        }));
        let contents = try!(f.read_to_string());
        let output = try!(BuildOutput::parse(contents.as_slice(),
                                             pkg_name.as_slice()));
        build_state.insert(id, req, output);

        fresh(tx)
    };

    Ok((dirty, fresh, freshness))
}

impl BuildState {
    pub fn new(config: super::BuildConfig,
               packages: &PackageSet) -> BuildState {
        let mut sources = HashMap::new();
        for package in packages.iter() {
            match package.get_manifest().get_links() {
                Some(links) => {
                    sources.insert(links.to_string(),
                                   package.get_package_id().clone());
                }
                None => {}
            }
        }
        let mut outputs = HashMap::new();
        let i1 = config.host.overrides.into_iter().map(|p| (p, Kind::Host));
        let i2 = config.target.overrides.into_iter().map(|p| (p, Kind::Target));
        for ((name, output), kind) in i1.chain(i2) {
            match sources.get(&name) {
                Some(id) => { outputs.insert((id.clone(), kind), output); }

                // If no package is using the library named `name`, then this is
                // just an override that we ignore.
                None => {}
            }
        }
        BuildState { outputs: Mutex::new(outputs) }
    }

    fn insert(&self, id: PackageId, req: Platform,
              output: BuildOutput) {
        let mut outputs = self.outputs.lock();
        match req {
            Platform::Target => { outputs.insert((id, Kind::Target), output); }
            Platform::Plugin => { outputs.insert((id, Kind::Host), output); }

            // If this build output was for both the host and target platforms,
            // we need to insert it at both places.
            Platform::PluginAndTarget => {
                outputs.insert((id.clone(), Kind::Host), output.clone());
                outputs.insert((id, Kind::Target), output);
            }
        }
    }
}

impl BuildOutput {
    // Parses the output of a script.
    // The `pkg_name` is used for error messages.
    pub fn parse(input: &str, pkg_name: &str) -> CargoResult<BuildOutput> {
        let mut library_paths = Vec::new();
        let mut library_links = Vec::new();
        let mut metadata = Vec::new();
        let whence = format!("build script of `{}`", pkg_name);

        for line in input.lines() {
            let mut iter = line.splitn(1, |c: char| c == ':');
            if iter.next() != Some("cargo") {
                // skip this line since it doesn't start with "cargo:"
                continue;
            }
            let data = match iter.next() {
                Some(val) => val,
                None => continue
            };

            // getting the `key=value` part of the line
            let mut iter = data.splitn(1, |c: char| c == '=');
            let key = iter.next();
            let value = iter.next();
            let (key, value) = match (key, value) {
                (Some(a), Some(b)) => (a, b.trim_right()),
                // line started with `cargo:` but didn't match `key=value`
                _ => return Err(human(format!("Wrong output in {}: `{}`",
                                              whence, line)))
            };

            if key == "rustc-flags" {
                let whence = whence.as_slice();
                let (libs, links) = try!(
                    BuildOutput::parse_rustc_flags(value, whence)
                );
                library_links.extend(links.into_iter());
                library_paths.extend(libs.into_iter());
            } else {
                metadata.push((key.to_string(), value.to_string()))
            }
        }

        Ok(BuildOutput {
            library_paths: library_paths,
            library_links: library_links,
            metadata: metadata,
        })
    }

    pub fn parse_rustc_flags(value: &str, whence: &str)
                             -> CargoResult<(Vec<Path>, Vec<String>)> {
        // TODO: some arguments (like paths) may contain spaces
        let value = value.trim();
        let mut flags_iter = value.words();
        let (mut library_links, mut library_paths) = (Vec::new(), Vec::new());
        loop {
            let flag = match flags_iter.next() {
                Some(f) => f,
                None => break
            };
            if flag != "-l" && flag != "-L" {
                return Err(human(format!("Only `-l` and `-L` flags are allowed \
                                         in {}: `{}`",
                                         whence, value)))
            }
            let value = match flags_iter.next() {
                Some(v) => v,
                None => return Err(human(format!("Flag in rustc-flags has no value \
                                                  in {}: `{}`",
                                                  whence, value)))
            };
            match flag {
                "-l" => library_links.push(value.to_string()),
                "-L" => library_paths.push(Path::new(value)),

                // was already checked above
                _ => return Err(human("only -l and -L flags are allowed"))
            };
        }
        Ok((library_paths, library_links))
    }
}

impl fmt::Show for BuildOutput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BuildOutput {{ paths: [..], libs: {}, metadata: {} }}",
               self.library_links, self.metadata)
    }
}
<|endoftext|>