<commit_before>//! Intrinsics and other functions that the miri engine executes without
//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
//! and miri.

use syntax::symbol::Symbol;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
use rustc::mir::BinOp;
use rustc::mir::interpret::{
    EvalResult, InterpError, Scalar,
};

use super::{
    Machine, PlaceTy, OpTy, InterpretCx,
};

mod type_name;

pub use type_name::*;

fn numeric_intrinsic<'tcx, Tag>(
    name: &str,
    bits: u128,
    kind: Primitive,
) -> EvalResult<'tcx, Scalar<Tag>> {
    let size = match kind {
        Primitive::Int(integer, _) => integer.size(),
        _ => bug!("invalid `{}` argument: {:?}", name, bits),
    };
    let extra = 128 - size.bits() as u128;
    let bits_out = match name {
        "ctpop" => bits.count_ones() as u128,
        "ctlz" => bits.leading_zeros() as u128 - extra,
        "cttz" => (bits << extra).trailing_zeros() as u128 - extra,
        "bswap" => (bits << extra).swap_bytes(),
        "bitreverse" => (bits << extra).reverse_bits(),
        _ => bug!("not a numeric intrinsic: {}", name),
    };
    Ok(Scalar::from_uint(bits_out, size))
}

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
    /// Returns `true` if emulation happened.
    pub fn emulate_intrinsic(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, bool> {
        let substs = instance.substs;

        let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
        match intrinsic_name {
            "min_align_of" => {
                let elem_ty = substs.type_at(0);
                let elem_align = self.layout_of(elem_ty)?.align.abi.bytes();
                let align_val = Scalar::from_uint(elem_align, dest.layout.size);
                self.write_scalar(align_val, dest)?;
            }

            "needs_drop" => {
                let ty = substs.type_at(0);
                let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env);
                let val = Scalar::from_bool(ty_needs_drop);
                self.write_scalar(val, dest)?;
            }

            "size_of" => {
                let ty = substs.type_at(0);
                let size = self.layout_of(ty)?.size.bytes() as u128;
                let size_val = Scalar::from_uint(size, dest.layout.size);
                self.write_scalar(size_val, dest)?;
            }

            "type_id" => {
                let ty = substs.type_at(0);
                let type_id = self.tcx.type_id_hash(ty) as u128;
                let id_val = Scalar::from_uint(type_id, dest.layout.size);
                self.write_scalar(id_val, dest)?;
            }

            "type_name" => {
                let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0));
                let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);
                let id_ptr = self.memory.tag_static_base_pointer(name_id.into());
                let alloc_len = alloc.bytes.len() as u64;
                let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self);
                self.write_immediate(name_val, dest)?;
            }

            | "ctpop"
            | "cttz"
            | "cttz_nonzero"
            | "ctlz"
            | "ctlz_nonzero"
            | "bswap"
            | "bitreverse" => {
                let ty = substs.type_at(0);
                let layout_of = self.layout_of(ty)?;
                let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
                let kind = match layout_of.abi {
                    ty::layout::Abi::Scalar(ref scalar) => scalar.value,
                    _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?,
                };
                let out_val = if intrinsic_name.ends_with("_nonzero") {
                    if bits == 0 {
                        return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
                    }
                    numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
                } else {
                    numeric_intrinsic(intrinsic_name, bits, kind)?
                };
                self.write_scalar(out_val, dest)?;
            }
            | "overflowing_add"
            | "overflowing_sub"
            | "overflowing_mul"
            | "add_with_overflow"
            | "sub_with_overflow"
            | "mul_with_overflow" => {
                let lhs = self.read_immediate(args[0])?;
                let rhs = self.read_immediate(args[1])?;
                let (bin_op, ignore_overflow) = match intrinsic_name {
                    "overflowing_add" => (BinOp::Add, true),
                    "overflowing_sub" => (BinOp::Sub, true),
                    "overflowing_mul" => (BinOp::Mul, true),
                    "add_with_overflow" => (BinOp::Add, false),
                    "sub_with_overflow" => (BinOp::Sub, false),
                    "mul_with_overflow" => (BinOp::Mul, false),
                    _ => bug!("Already checked for int ops")
                };
                if ignore_overflow {
                    self.binop_ignore_overflow(bin_op, lhs, rhs, dest)?;
                } else {
                    self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
                }
            }
            "saturating_add" | "saturating_sub" => {
                let l = self.read_immediate(args[0])?;
                let r = self.read_immediate(args[1])?;
                let is_add = intrinsic_name == "saturating_add";
                let (val, overflowed) = self.binary_op(if is_add {
                    BinOp::Add
                } else {
                    BinOp::Sub
                }, l, r)?;
                let val = if overflowed {
                    let num_bits = l.layout.size.bits();
                    if l.layout.abi.is_signed() {
                        // For signed ints the saturated value depends on the sign of the first
                        // term since the sign of the second term can be inferred from this and
                        // the fact that the operation has overflowed (if either is 0 no
                        // overflow can occur)
                        let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
                        let first_term_positive = first_term & (1 << (num_bits-1)) == 0;
                        if first_term_positive {
                            // Negative overflow not possible since the positive first term
                            // can only increase an (in range) negative term for addition
                            // or corresponding negated positive term for subtraction
                            Scalar::from_uint((1u128 << (num_bits - 1)) - 1,  // max positive
                                Size::from_bits(num_bits))
                        } else {
                            // Positive overflow not possible for similar reason
                            // max negative
                            Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
                        }
                    } else {  // unsigned
                        if is_add {
                            // max unsigned
                            Scalar::from_uint(u128::max_value() >> (128 - num_bits),
                                Size::from_bits(num_bits))
                        } else {  // underflow to 0
                            Scalar::from_uint(0u128, Size::from_bits(num_bits))
                        }
                    }
                } else {
                    val
                };
                self.write_scalar(val, dest)?;
            }
            "unchecked_shl" | "unchecked_shr" => {
                let l = self.read_immediate(args[0])?;
                let r = self.read_immediate(args[1])?;
                let bin_op = match intrinsic_name {
                    "unchecked_shl" => BinOp::Shl,
                    "unchecked_shr" => BinOp::Shr,
                    _ => bug!("Already checked for int ops")
                };
                let (val, overflowed) = self.binary_op(bin_op, l, r)?;
                if overflowed {
                    let layout = self.layout_of(substs.type_at(0))?;
                    let r_val =  r.to_scalar()?.to_bits(layout.size)?;
                    return err!(Intrinsic(
                        format!("Overflowing shift by {} in {}", r_val, intrinsic_name),
                    ));
                }
                self.write_scalar(val, dest)?;
            }
            "rotate_left" | "rotate_right" => {
                // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
                // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
                let layout = self.layout_of(substs.type_at(0))?;
                let val_bits = self.read_scalar(args[0])?.to_bits(layout.size)?;
                let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?;
                let width_bits = layout.size.bits() as u128;
                let shift_bits = raw_shift_bits % width_bits;
                let inv_shift_bits = (width_bits - raw_shift_bits) % width_bits;
                let result_bits = if intrinsic_name == "rotate_left" {
                    (val_bits << shift_bits) | (val_bits >> inv_shift_bits)
                } else {
                    (val_bits >> shift_bits) | (val_bits << inv_shift_bits)
                };
                let truncated_bits = self.truncate(result_bits, layout);
                let result = Scalar::from_uint(truncated_bits, layout.size);
                self.write_scalar(result, dest)?;
            }
            "transmute" => {
                self.copy_op_transmute(args[0], dest)?;
            }

            _ => return Ok(false),
        }

        Ok(true)
    }

    /// "Intercept" a function call because we have something special to do for it.
    /// Returns `true` if an intercept happened.
    pub fn hook_fn(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: Option<PlaceTy<'tcx, M::PointerTag>>,
    ) -> EvalResult<'tcx, bool> {
        let def_id = instance.def_id();
        // Some fn calls are actually BinOp intrinsics
        if let Some((op, oflo)) = self.tcx.is_binop_lang_item(def_id) {
            let dest = dest.expect("128 lowerings can't diverge");
            let l = self.read_immediate(args[0])?;
            let r = self.read_immediate(args[1])?;
            if oflo {
                self.binop_with_overflow(op, l, r, dest)?;
            } else {
                self.binop_ignore_overflow(op, l, r, dest)?;
            }
            return Ok(true);
        } else if Some(def_id) == self.tcx.lang_items().panic_fn() {
            assert!(args.len() == 1);
            // &(&'static str, &'static str, u32, u32)
            let place = self.deref_operand(args[0])?;
            let (msg, file, line, col) = (
                self.mplace_field(place, 0)?,
                self.mplace_field(place, 1)?,
                self.mplace_field(place, 2)?,
                self.mplace_field(place, 3)?,
            );

            let msg_place = self.deref_operand(msg.into())?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let file_place = self.deref_operand(file.into())?;
            let file = Symbol::intern(self.read_str(file_place)?);
            let line = self.read_scalar(line.into())?.to_u32()?;
            let col = self.read_scalar(col.into())?.to_u32()?;
            return Err(InterpError::Panic { msg, file, line, col }.into());
        } else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
            assert!(args.len() == 2);
            // &'static str, &(&'static str, u32, u32)
            let msg = args[0];
            let place = self.deref_operand(args[1])?;
            let (file, line, col) = (
                self.mplace_field(place, 0)?,
                self.mplace_field(place, 1)?,
                self.mplace_field(place, 2)?,
            );

            let msg_place = self.deref_operand(msg.into())?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let file_place = self.deref_operand(file.into())?;
            let file = Symbol::intern(self.read_str(file_place)?);
            let line = self.read_scalar(line.into())?.to_u32()?;
            let col = self.read_scalar(col.into())?.to_u32()?;
            return Err(InterpError::Panic { msg, file, line, col }.into());
        } else {
            return Ok(false);
        }
    }
}
<commit_msg>Re-add needed Immediate dependency<commit_after>//! Intrinsics and other functions that the miri engine executes without
//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
//! and miri.

use syntax::symbol::Symbol;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
use rustc::mir::BinOp;
use rustc::mir::interpret::{
    EvalResult, InterpError, Scalar,
};

use super::{
    Machine, PlaceTy, OpTy, InterpretCx, Immediate,
};

mod type_name;

pub use type_name::*;

fn numeric_intrinsic<'tcx, Tag>(
    name: &str,
    bits: u128,
    kind: Primitive,
) -> EvalResult<'tcx, Scalar<Tag>> {
    let size = match kind {
        Primitive::Int(integer, _) => integer.size(),
        _ => bug!("invalid `{}` argument: {:?}", name, bits),
    };
    let extra = 128 - size.bits() as u128;
    let bits_out = match name {
        "ctpop" => bits.count_ones() as u128,
        "ctlz" => bits.leading_zeros() as u128 - extra,
        "cttz" => (bits << extra).trailing_zeros() as u128 - extra,
        "bswap" => (bits << extra).swap_bytes(),
        "bitreverse" => (bits << extra).reverse_bits(),
        _ => bug!("not a numeric intrinsic: {}", name),
    };
    Ok(Scalar::from_uint(bits_out, size))
}

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
    /// Returns `true` if emulation happened.
    pub fn emulate_intrinsic(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, bool> {
        let substs = instance.substs;

        let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
        match intrinsic_name {
            "min_align_of" => {
                let elem_ty = substs.type_at(0);
                let elem_align = self.layout_of(elem_ty)?.align.abi.bytes();
                let align_val = Scalar::from_uint(elem_align, dest.layout.size);
                self.write_scalar(align_val, dest)?;
            }

            "needs_drop" => {
                let ty = substs.type_at(0);
                let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env);
                let val = Scalar::from_bool(ty_needs_drop);
                self.write_scalar(val, dest)?;
            }

            "size_of" => {
                let ty = substs.type_at(0);
                let size = self.layout_of(ty)?.size.bytes() as u128;
                let size_val = Scalar::from_uint(size, dest.layout.size);
                self.write_scalar(size_val, dest)?;
            }

            "type_id" => {
                let ty = substs.type_at(0);
                let type_id = self.tcx.type_id_hash(ty) as u128;
                let id_val = Scalar::from_uint(type_id, dest.layout.size);
                self.write_scalar(id_val, dest)?;
            }

            "type_name" => {
                let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0));
                let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);
                let id_ptr = self.memory.tag_static_base_pointer(name_id.into());
                let alloc_len = alloc.bytes.len() as u64;
                let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self);
                self.write_immediate(name_val, dest)?;
            }

            | "ctpop"
            | "cttz"
            | "cttz_nonzero"
            | "ctlz"
            | "ctlz_nonzero"
            | "bswap"
            | "bitreverse" => {
                let ty = substs.type_at(0);
                let layout_of = self.layout_of(ty)?;
                let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
                let kind = match layout_of.abi {
                    ty::layout::Abi::Scalar(ref scalar) => scalar.value,
                    _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?,
                };
                let out_val = if intrinsic_name.ends_with("_nonzero") {
                    if bits == 0 {
                        return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
                    }
                    numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
                } else {
                    numeric_intrinsic(intrinsic_name, bits, kind)?
                };
                self.write_scalar(out_val, dest)?;
            }
            | "overflowing_add"
            | "overflowing_sub"
            | "overflowing_mul"
            | "add_with_overflow"
            | "sub_with_overflow"
            | "mul_with_overflow" => {
                let lhs = self.read_immediate(args[0])?;
                let rhs = self.read_immediate(args[1])?;
                let (bin_op, ignore_overflow) = match intrinsic_name {
                    "overflowing_add" => (BinOp::Add, true),
                    "overflowing_sub" => (BinOp::Sub, true),
                    "overflowing_mul" => (BinOp::Mul, true),
                    "add_with_overflow" => (BinOp::Add, false),
                    "sub_with_overflow" => (BinOp::Sub, false),
                    "mul_with_overflow" => (BinOp::Mul, false),
                    _ => bug!("Already checked for int ops")
                };
                if ignore_overflow {
                    self.binop_ignore_overflow(bin_op, lhs, rhs, dest)?;
                } else {
                    self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
                }
            }
            "saturating_add" | "saturating_sub" => {
                let l = self.read_immediate(args[0])?;
                let r = self.read_immediate(args[1])?;
                let is_add = intrinsic_name == "saturating_add";
                let (val, overflowed) = self.binary_op(if is_add {
                    BinOp::Add
                } else {
                    BinOp::Sub
                }, l, r)?;
                let val = if overflowed {
                    let num_bits = l.layout.size.bits();
                    if l.layout.abi.is_signed() {
                        // For signed ints the saturated value depends on the sign of the first
                        // term since the sign of the second term can be inferred from this and
                        // the fact that the operation has overflowed (if either is 0 no
                        // overflow can occur)
                        let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
                        let first_term_positive = first_term & (1 << (num_bits-1)) == 0;
                        if first_term_positive {
                            // Negative overflow not possible since the positive first term
                            // can only increase an (in range) negative term for addition
                            // or corresponding negated positive term for subtraction
                            Scalar::from_uint((1u128 << (num_bits - 1)) - 1,  // max positive
                                Size::from_bits(num_bits))
                        } else {
                            // Positive overflow not possible for similar reason
                            // max negative
                            Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
                        }
                    } else {  // unsigned
                        if is_add {
                            // max unsigned
                            Scalar::from_uint(u128::max_value() >> (128 - num_bits),
                                Size::from_bits(num_bits))
                        } else {  // underflow to 0
                            Scalar::from_uint(0u128, Size::from_bits(num_bits))
                        }
                    }
                } else {
                    val
                };
                self.write_scalar(val, dest)?;
            }
            "unchecked_shl" | "unchecked_shr" => {
                let l = self.read_immediate(args[0])?;
                let r = self.read_immediate(args[1])?;
                let bin_op = match intrinsic_name {
                    "unchecked_shl" => BinOp::Shl,
                    "unchecked_shr" => BinOp::Shr,
                    _ => bug!("Already checked for int ops")
                };
                let (val, overflowed) = self.binary_op(bin_op, l, r)?;
                if overflowed {
                    let layout = self.layout_of(substs.type_at(0))?;
                    let r_val =  r.to_scalar()?.to_bits(layout.size)?;
                    return err!(Intrinsic(
                        format!("Overflowing shift by {} in {}", r_val, intrinsic_name),
                    ));
                }
                self.write_scalar(val, dest)?;
            }
            "rotate_left" | "rotate_right" => {
                // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
                // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
                let layout = self.layout_of(substs.type_at(0))?;
                let val_bits = self.read_scalar(args[0])?.to_bits(layout.size)?;
                let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?;
                let width_bits = layout.size.bits() as u128;
                let shift_bits = raw_shift_bits % width_bits;
                let inv_shift_bits = (width_bits - raw_shift_bits) % width_bits;
                let result_bits = if intrinsic_name == "rotate_left" {
                    (val_bits << shift_bits) | (val_bits >> inv_shift_bits)
                } else {
                    (val_bits >> shift_bits) | (val_bits << inv_shift_bits)
                };
                let truncated_bits = self.truncate(result_bits, layout);
                let result = Scalar::from_uint(truncated_bits, layout.size);
                self.write_scalar(result, dest)?;
            }
            "transmute" => {
                self.copy_op_transmute(args[0], dest)?;
            }

            _ => return Ok(false),
        }

        Ok(true)
    }

    /// "Intercept" a function call because we have something special to do for it.
    /// Returns `true` if an intercept happened.
    pub fn hook_fn(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: Option<PlaceTy<'tcx, M::PointerTag>>,
    ) -> EvalResult<'tcx, bool> {
        let def_id = instance.def_id();
        // Some fn calls are actually BinOp intrinsics
        if let Some((op, oflo)) = self.tcx.is_binop_lang_item(def_id) {
            let dest = dest.expect("128 lowerings can't diverge");
            let l = self.read_immediate(args[0])?;
            let r = self.read_immediate(args[1])?;
            if oflo {
                self.binop_with_overflow(op, l, r, dest)?;
            } else {
                self.binop_ignore_overflow(op, l, r, dest)?;
            }
            return Ok(true);
        } else if Some(def_id) == self.tcx.lang_items().panic_fn() {
            assert!(args.len() == 1);
            // &(&'static str, &'static str, u32, u32)
            let place = self.deref_operand(args[0])?;
            let (msg, file, line, col) = (
                self.mplace_field(place, 0)?,
                self.mplace_field(place, 1)?,
                self.mplace_field(place, 2)?,
                self.mplace_field(place, 3)?,
            );

            let msg_place = self.deref_operand(msg.into())?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let file_place = self.deref_operand(file.into())?;
            let file = Symbol::intern(self.read_str(file_place)?);
            let line = self.read_scalar(line.into())?.to_u32()?;
            let col = self.read_scalar(col.into())?.to_u32()?;
            return Err(InterpError::Panic { msg, file, line, col }.into());
        } else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
            assert!(args.len() == 2);
            // &'static str, &(&'static str, u32, u32)
            let msg = args[0];
            let place = self.deref_operand(args[1])?;
            let (file, line, col) = (
                self.mplace_field(place, 0)?,
                self.mplace_field(place, 1)?,
                self.mplace_field(place, 2)?,
            );

            let msg_place = self.deref_operand(msg.into())?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let file_place = self.deref_operand(file.into())?;
            let file = Symbol::intern(self.read_str(file_place)?);
            let line = self.read_scalar(line.into())?.to_u32()?;
            let col = self.read_scalar(col.into())?.to_u32()?;
            return Err(InterpError::Panic { msg, file, line, col }.into());
        } else {
            return Ok(false);
        }
    }
}
<|endoftext|>


<commit_before>// check-pass

#![deny(deprecated)]

#![crate_type = "proc-macro"]

extern crate proc_macro;
use proc_macro::*;

#[proc_macro]
#[deprecated(since = "1.0.0", note = "test")]
pub fn test_compile_without_warning_with_deprecated(_: TokenStream) -> TokenStream {
    TokenStream::new()
}
<commit_msg>Deprecated proc_macro doesn't trigger warning on build library<commit_after>// check-pass
// force-host
// no-prefer-dynamic

#![deny(deprecated)]

#![crate_type = "proc-macro"]

extern crate proc_macro;
use proc_macro::*;

#[proc_macro]
#[deprecated(since = "1.0.0", note = "test")]
pub fn test_compile_without_warning_with_deprecated(_: TokenStream) -> TokenStream {
    TokenStream::new()
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

    pub fn len(&self) -> usize {
        self.buffers.len()
    }

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.buffers.is_empty()
    }

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    /// Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    /// assigned it is never changed. They can be reused, or even not used (we only allocate them
    /// for our convenience, and they do not need to go up monotonically like buffer ids do).
    /// For new buffers not backed by a file "new", then "new 1 " etc.
    /// For buffers backed by a file, the leaf filename, then '1' etc.
    fn get_unique_title(&self, proposed: &str) -> String {
        // let prefix = String::from(proposed) + " ";
        // let matching_buffers : Vec<String> = self.buffers.values()
        //     .map(|refcell| refcell.borrow())
        //     .map(|x| x.title.clone())
        //     .filter(|title| *title == String::from(proposed) || title.starts_with(&prefix))
        //     .collect();

        let titles : Vec<_> = self.buffers.values().map(|refcell| refcell.borrow().title.clone()).collect();

        //let titles2 : Vec<_> = self.buffers.values().map(|refcell| *(refcell.borrow().title)).collect();

        inner_get_unique_title(proposed, &titles)
    }
}

fn inner_get_unique_title(proposed: &str, current_titles: &[String]) -> String {
    let namer = |n: i32| -> String {
        if n == 0 {
            return String::from(proposed)
        } else {
            return String::from(proposed) + " " + &n.to_string()
        }
    };

    let mut i = 0;
    loop {
        let p = namer(i);
        if !current_titles.contains(&p) {
            return p
        } else {
            i += 1
        }
    }
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use super::super::BufferFactory;

    #[test]
    fn get_unique_title_for_empty_collection_returns_proposed() {
        let bc = BufferCollection::new();
        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_no_matching_buffer_title_returns_proposed() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_title_returns_proposed_with_numeral_of_one() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 1");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_in_ascending_order_returns_proposed_with_next_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 3");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_with_gap_returns_proposed_with_lowest_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 3");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 2");
    }

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<commit_msg>Add before Linux reinstall.<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::{Ref, RefCell};
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

    pub fn len(&self) -> usize {
        self.buffers.len()
    }

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.buffers.is_empty()
    }

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    fn all_buffers(&self) -> Vec<Ref<Buffer>> {
        let x : Vec<_> = self.buffers.values().map(|rcb| rcb.borrow()).collect();
        x
    }

    /// Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    /// assigned it is never changed. They can be reused, or even not used (we only allocate them
    /// for our convenience, and they do not need to go up monotonically like buffer ids do).
    /// For new buffers not backed by a file "new", then "new 1 " etc.
    /// For buffers backed by a file, the leaf filename, then '1' etc.
    fn get_unique_title(&self, proposed: &str) -> String {
        //let titles : Vec<_> = self.buffers.values().map(|refcell| refcell.borrow().title.clone()).collect();
        let titles : Vec<_> = self.all_buffers().iter().map(|x| x.title.clone()).collect();

        inner_get_unique_title(proposed, &titles)
    }
}

fn inner_get_unique_title(proposed: &str, current_titles: &[String]) -> String {
    let namer = |n: i32| -> String {
        if n == 0 {
            return String::from(proposed)
        } else {
            return String::from(proposed) + " " + &n.to_string()
        }
    };

    let mut i = 0;
    loop {
        let p = namer(i);
        if !current_titles.contains(&p) {
            return p
        } else {
            i += 1
        }
    }
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use super::super::BufferFactory;

    #[test]
    fn get_unique_title_for_empty_collection_returns_proposed() {
        let bc = BufferCollection::new();
        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_no_matching_buffer_title_returns_proposed() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_title_returns_proposed_with_numeral_of_one() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 1");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_in_ascending_order_returns_proposed_with_next_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 3");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_with_gap_returns_proposed_with_lowest_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 3");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 2");
    }

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<|endoftext|>


<commit_before>//! `Tombstone` data description.
use crate::data::RoomName;

use super::creep::CreepPartType;

with_resource_fields_and_update_struct! {
    // Unfortunately, nested macros are not allowed, so we list all resource
    // types manually.
    //
    // This is copy-pasted from `resources.rs`, and any updates here should also be updated
    // there.
    //
    // see: https://github.com/rust-lang/rust/issues/35853
    {
        crate::websocket::types::room::resources::ResourceType;

        Energy => energy => "energy"
            => Some(crate::websocket::types::room::resources::ResourceType::Power);
        Power => power => "power"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydrogen);
        Hydrogen => hydrogen => "H"
            => Some(crate::websocket::types::room::resources::ResourceType::Oxygen);
        Oxygen => oxygen => "O"
            => Some(crate::websocket::types::room::resources::ResourceType::Utrium);
        Utrium => utrium => "U"
            => Some(crate::websocket::types::room::resources::ResourceType::Lemergium);
        Lemergium => lemergium => "L"
            => Some(crate::websocket::types::room::resources::ResourceType::Keanium);
        Keanium => keanium => "K"
            => Some(crate::websocket::types::room::resources::ResourceType::Zynthium);
        Zynthium => zynthium => "Z"
            => Some(crate::websocket::types::room::resources::ResourceType::Catalyst);
        Catalyst => catalyst => "X"
            => Some(crate::websocket::types::room::resources::ResourceType::Ghodium);
        Ghodium => ghodium => "G"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydroxide);
        Hydroxide => hydroxide => "OH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumKeanite);
        ZynthiumKeanite => zynthium_keanite => "ZK"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumLemergite);
        UtriumLemergite => utrium_lemergite => "UL"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumHydride);
        UtriumHydride => utrium_hydride => "UH"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumOxide);
        UtriumOxide => utrium_oxide => "UO"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumHydride);
        KeaniumHydride => keanium_hydride => "KH"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumOxide);
        KeaniumOxide => keanium_oxide => "KO"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumHydride);
        LemergiumHydride => lemergium_hydride => "LH"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumOxide);
        LemergiumOxide => lemergium_oxide => "LO"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumHydride);
        ZynthiumHydride => zynthium_hydride => "ZH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumOxide);
        ZynthiumOxide => zynthium_oxide => "ZO"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumHydride);
        GhodiumHydride => ghodium_hydride => "GH"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumOxide);
        GhodiumOxide => ghodium_oxide => "GO"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAcid);
        UtriumAcid => utrium_acid => "UH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAlkalide);
        UtriumAlkalide => utrium_alkalide => "UHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAcid);
        KeaniumAcid => keanium_acid => "KH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAlkalide);
        KeaniumAlkalide => keanium_alkalide => "KHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAcid);
        LemergiumAcid => lemergium_acid => "LH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAlkalide);
        LemergiumAlkalide => lemergium_alkalide => "LHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAcid);
        ZynthiumAcid => zynthium_acid => "ZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAlkalide);
        ZynthiumAlkalide => zynthium_alkalide => "ZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAcid);
        GhodiumAcid => ghodium_acid => "GH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAlkalide);
        GhodiumAlkalide => ghodium_alkalide => "GHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAcid);
        CatalyzedUtriumAcid => catalyzed_utrium_acid => "XUH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAlkalide);
        CatalyzedUtriumAlkalide => catalyzed_utrium_alkalide => "XUHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAcid);
        CatalyzedKeaniumAcid => catalyzed_keanium_acid => "XKH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAlkalide);
        CatalyzedKeaniumAlkalide => catalyzed_keanium_alkalide => "XKHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAcid);
        CatalyzedLemergiumAcid => catalyzed_lemergium_acid => "XLH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAlkalide);
        CatalyzedLemergiumAlkalide => catalyzed_lemergium_alkalide => "XLHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAcid);
        CatalyzedZynthiumAcid => catalyzed_zynthium_acid => "XZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAlkalide);
        CatalyzedZynthiumAlkalide => catalyzed_zynthium_alkalide => "XZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAcid);
        CatalyzedGhodiumAcid => catalyzed_ghodium_acid => "XGH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAlkalide);
        CatalyzedGhodiumAlkalide => catalyzed_ghodium_alkalide => "XGHO2"
            => None;
    }

    /// A tomstone - remnants of a dead creep
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct Tombstone {
        /// The user ID of the owner of the creep
        pub user: String,
        /// The body of the creep who died
        pub creep_body: Vec<CreepPartType>,
        /// The ID of the creep who died
        pub creep_id: String,
        /// The name of the creep who died
        pub creep_name: String,
        /// What the creep was saying when they died
        pub creep_saying: Option<String>,
        /// How many ticks-to-live did the creeps have when it died
        pub creep_ticks_to_live: i32,
        /// The time of death of the creep
        pub death_time: u32,
        /// The time at which this structure will decay
        pub decay_time: u32,
        // TODO: what does the tombstone of a power creep look like?
    }

    /// The update structure for a `Tombstone`.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct TombstoneUpdate { ... }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use super::Tombstone;

    #[test]
    fn parse_simple_tombstone() {
        let json = json!({
            "_id": "5ce0a11dcd8deb5a978cb216",
            "creepBody": [
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "move",
                "move",
                "move",
                "move",
                "move"
            ],
            "creepId": "5ce08e9f184f823e92616faf",
            "creepName": "HeavyConsolidator6921549",
            "creepSaying": null,
            "creepTicksToLive": 1,
            "deathTime": 6923092,
            "decayTime": 6923167,
            "room": "E8S29",
            "type": "tombstone",
            "user": "5ca80c8f3c33e30c8e85555d",
            "x": 30,
            "y": 31
        });

        let mut obj = Tombstone::deserialize(json).unwrap();

        assert_eq!(obj.creep_id, "5ce08e9f184f823e92616faf");
        assert_eq!(obj.creep_name, "HeavyConsolidator6921549");
    }

    fn parse_tombstone_with_energy() {
        let json = json!({
            "_id": "5ce0a4839c5bd560bebb03e9",
            "creepBody": [
                "move",
                "move",
                "carry",
                "work"
            ],
            "creepId": "5ce098c5c4e055067fbf182e",
            "creepName": "6922398-0",
            "creepSaying": null,
            "creepTicksToLive": 532,
            "deathTime": 6923377,
            "decayTime": 6923397,
            "energy": 44,
            "room": "E9S31",
            "type": "tombstone",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 33,
            "y": 23
        });

        let mut obj = Tombstone::deserialize(json).unwrap();

        assert_eq!(obj.creep_id, "5ce098c5c4e055067fbf182e");
        assert_eq!(obj.creep_name, "6922398-0");
        assert_eq!(obj.energy, 44);
    }
}
<commit_msg>Fix tombstone tests.<commit_after>//! `Tombstone` data description.
use crate::data::RoomName;

use super::creep::CreepPartType;

with_resource_fields_and_update_struct! {
    // Unfortunately, nested macros are not allowed, so we list all resource
    // types manually.
    //
    // This is copy-pasted from `resources.rs`, and any updates here should also be updated
    // there.
    //
    // see: https://github.com/rust-lang/rust/issues/35853
    {
        crate::websocket::types::room::resources::ResourceType;

        Energy => energy => "energy"
            => Some(crate::websocket::types::room::resources::ResourceType::Power);
        Power => power => "power"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydrogen);
        Hydrogen => hydrogen => "H"
            => Some(crate::websocket::types::room::resources::ResourceType::Oxygen);
        Oxygen => oxygen => "O"
            => Some(crate::websocket::types::room::resources::ResourceType::Utrium);
        Utrium => utrium => "U"
            => Some(crate::websocket::types::room::resources::ResourceType::Lemergium);
        Lemergium => lemergium => "L"
            => Some(crate::websocket::types::room::resources::ResourceType::Keanium);
        Keanium => keanium => "K"
            => Some(crate::websocket::types::room::resources::ResourceType::Zynthium);
        Zynthium => zynthium => "Z"
            => Some(crate::websocket::types::room::resources::ResourceType::Catalyst);
        Catalyst => catalyst => "X"
            => Some(crate::websocket::types::room::resources::ResourceType::Ghodium);
        Ghodium => ghodium => "G"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydroxide);
        Hydroxide => hydroxide => "OH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumKeanite);
        ZynthiumKeanite => zynthium_keanite => "ZK"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumLemergite);
        UtriumLemergite => utrium_lemergite => "UL"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumHydride);
        UtriumHydride => utrium_hydride => "UH"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumOxide);
        UtriumOxide => utrium_oxide => "UO"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumHydride);
        KeaniumHydride => keanium_hydride => "KH"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumOxide);
        KeaniumOxide => keanium_oxide => "KO"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumHydride);
        LemergiumHydride => lemergium_hydride => "LH"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumOxide);
        LemergiumOxide => lemergium_oxide => "LO"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumHydride);
        ZynthiumHydride => zynthium_hydride => "ZH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumOxide);
        ZynthiumOxide => zynthium_oxide => "ZO"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumHydride);
        GhodiumHydride => ghodium_hydride => "GH"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumOxide);
        GhodiumOxide => ghodium_oxide => "GO"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAcid);
        UtriumAcid => utrium_acid => "UH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAlkalide);
        UtriumAlkalide => utrium_alkalide => "UHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAcid);
        KeaniumAcid => keanium_acid => "KH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAlkalide);
        KeaniumAlkalide => keanium_alkalide => "KHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAcid);
        LemergiumAcid => lemergium_acid => "LH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAlkalide);
        LemergiumAlkalide => lemergium_alkalide => "LHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAcid);
        ZynthiumAcid => zynthium_acid => "ZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAlkalide);
        ZynthiumAlkalide => zynthium_alkalide => "ZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAcid);
        GhodiumAcid => ghodium_acid => "GH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAlkalide);
        GhodiumAlkalide => ghodium_alkalide => "GHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAcid);
        CatalyzedUtriumAcid => catalyzed_utrium_acid => "XUH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAlkalide);
        CatalyzedUtriumAlkalide => catalyzed_utrium_alkalide => "XUHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAcid);
        CatalyzedKeaniumAcid => catalyzed_keanium_acid => "XKH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAlkalide);
        CatalyzedKeaniumAlkalide => catalyzed_keanium_alkalide => "XKHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAcid);
        CatalyzedLemergiumAcid => catalyzed_lemergium_acid => "XLH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAlkalide);
        CatalyzedLemergiumAlkalide => catalyzed_lemergium_alkalide => "XLHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAcid);
        CatalyzedZynthiumAcid => catalyzed_zynthium_acid => "XZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAlkalide);
        CatalyzedZynthiumAlkalide => catalyzed_zynthium_alkalide => "XZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAcid);
        CatalyzedGhodiumAcid => catalyzed_ghodium_acid => "XGH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAlkalide);
        CatalyzedGhodiumAlkalide => catalyzed_ghodium_alkalide => "XGHO2"
            => None;
    }

    /// A tomstone - remnants of a dead creep
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct Tombstone {
        /// The user ID of the owner of the creep
        pub user: String,
        /// The body of the creep who died
        pub creep_body: Vec<CreepPartType>,
        /// The ID of the creep who died
        pub creep_id: String,
        /// The name of the creep who died
        pub creep_name: String,
        /// What the creep was saying when they died
        pub creep_saying: Option<String>,
        /// How many ticks-to-live did the creeps have when it died
        pub creep_ticks_to_live: i32,
        /// The time of death of the creep
        pub death_time: u32,
        /// The time at which this structure will decay
        pub decay_time: u32,
        // TODO: what does the tombstone of a power creep look like?
    }

    /// The update structure for a `Tombstone`.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct TombstoneUpdate { ... }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use super::Tombstone;

    #[test]
    fn parse_simple_tombstone() {
        let json = json!({
            "_id": "5ce0a11dcd8deb5a978cb216",
            "creepBody": [
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "move",
                "move",
                "move",
                "move",
                "move"
            ],
            "creepId": "5ce08e9f184f823e92616faf",
            "creepName": "HeavyConsolidator6921549",
            "creepSaying": null,
            "creepTicksToLive": 1,
            "deathTime": 6923092,
            "decayTime": 6923167,
            "room": "E8S29",
            "type": "tombstone",
            "user": "5ca80c8f3c33e30c8e85555d",
            "x": 30,
            "y": 31
        });

        let obj = Tombstone::deserialize(json).unwrap();

        assert_eq!(obj.creep_id, "5ce08e9f184f823e92616faf");
        assert_eq!(obj.creep_name, "HeavyConsolidator6921549");
    }

    #[test]
    fn parse_tombstone_with_energy() {
        let json = json!({
            "_id": "5ce0a4839c5bd560bebb03e9",
            "creepBody": [
                "move",
                "move",
                "carry",
                "work"
            ],
            "creepId": "5ce098c5c4e055067fbf182e",
            "creepName": "6922398-0",
            "creepSaying": null,
            "creepTicksToLive": 532,
            "deathTime": 6923377,
            "decayTime": 6923397,
            "energy": 44,
            "room": "E9S31",
            "type": "tombstone",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 33,
            "y": 23
        });

        let obj = Tombstone::deserialize(json).unwrap();

        assert_eq!(obj.creep_id, "5ce098c5c4e055067fbf182e");
        assert_eq!(obj.creep_name, "6922398-0");
        assert_eq!(obj.energy, 44);
    }
}
<|endoftext|>


<commit_before>//! An interpreter for the rust-installer package format.  Responsible
//! for installing from a directory or tarball to an installation
//! prefix, represented by a `Components` instance.

extern crate tar;
extern crate flate2;

use component::components::*;
use component::transaction::*;

use errors::*;
use rustup_utils::utils;
use temp;

use std::path::{Path, PathBuf};
use std::collections::HashSet;
use std::fmt;
use std::io::Read;
use std::fs::File;

/// The current metadata revision used by rust-installer
pub const INSTALLER_VERSION: &'static str = "3";
pub const VERSION_FILE: &'static str = "rust-installer-version";

pub trait Package: fmt::Debug {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool;
    fn install<'a>(&self,
                   target: &Components,
                   component: &str,
                   short_name: Option<&str>,
                   tx: Transaction<'a>)
                   -> Result<Transaction<'a>>;
    fn components(&self) -> Vec<String>;
}

#[derive(Debug)]
pub struct DirectoryPackage {
    path: PathBuf,
    components: HashSet<String>,
}

impl DirectoryPackage {
    pub fn new(path: PathBuf) -> Result<Self> {
        try!(validate_installer_version(&path));

        let content = try!(utils::read_file("package components", &path.join("components")));
        let components = content.lines().map(|l| l.to_owned()).collect();
        Ok(DirectoryPackage {
            path: path,
            components: components,
        })
    }
}

fn validate_installer_version(path: &Path) -> Result<()> {
    let file = try!(utils::read_file("installer version", &path.join(VERSION_FILE)));
    let v = file.trim();
    if v == INSTALLER_VERSION {
        Ok(())
    } else {
        Err(ErrorKind::BadInstallerVersion(v.to_owned()).into())
    }
}

impl Package for DirectoryPackage {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.components.contains(component) ||
        if let Some(n) = short_name {
            self.components.contains(n)
        } else {
            false
        }
    }
    fn install<'a>(&self,
                   target: &Components,
                   name: &str,
                   short_name: Option<&str>,
                   tx: Transaction<'a>)
                   -> Result<Transaction<'a>> {
        let actual_name = if self.components.contains(name) {
            name
        } else if let Some(n) = short_name {
            n
        } else {
            name
        };

        let root = self.path.join(actual_name);

        let manifest = try!(utils::read_file("package manifest", &root.join("manifest.in")));
        let mut builder = target.add(name, tx);

        for l in manifest.lines() {
            let part = try!(ComponentPart::decode(l)
                            .ok_or_else(|| ErrorKind::CorruptComponent(name.to_owned())));

            let path = part.1;
            let src_path = root.join(&path);

            match &*part.0 {
                "file" => try!(builder.copy_file(path.clone(), &src_path)),
                "dir" => try!(builder.copy_dir(path.clone(), &src_path)),
                _ => return Err(ErrorKind::CorruptComponent(name.to_owned()).into()),
            }

            try!(set_file_perms(&target.prefix().path().join(path), &src_path));
        }

        let tx = try!(builder.finish());

        Ok(tx)
    }

    fn components(&self) -> Vec<String> {
        self.components.iter().cloned().collect()
    }
}

// On Unix we need to set up the file permissions correctly so
// binaries are executable and directories readable. This shouldn't be
// necessary: the source files *should* have the right permissions,
// but due to rust-lang/rust#25479 they don't.
#[cfg(unix)]
fn set_file_perms(dest_path: &Path, src_path: &Path) -> Result<()> {
    use std::fs;
    use std::os::unix::fs::PermissionsExt;
    use walkdir::WalkDir;

    // By convention, anything in the bin/ directory of the package is a binary
    let is_bin = if let Some(p) = src_path.parent() {
        p.ends_with("bin")
    } else {
        false
    };

    let is_dir = utils::is_directory(dest_path);

    if is_dir {
        // Walk the directory setting everything
        for entry in WalkDir::new(dest_path) {
            let entry = try!(entry.chain_err(|| ErrorKind::ComponentDirPermissionsFailed));
            let meta = try!(entry.metadata().chain_err(|| ErrorKind::ComponentDirPermissionsFailed));
            if meta.is_dir() {
                let mut perm = meta.permissions();
                perm.set_mode(0o755);
                try!(fs::set_permissions(entry.path(), perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
            } else {
                let mut perm = meta.permissions();
                perm.set_mode(0o644);
                try!(fs::set_permissions(entry.path(), perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
            }
        }
    } else if is_bin {
        let mut perm = try!(fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed))
                           .permissions();
        perm.set_mode(0o755);
        try!(fs::set_permissions(dest_path, perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
    } else {
        let mut perm = try!(fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed))
                           .permissions();
        perm.set_mode(0o644);
        try!(fs::set_permissions(dest_path, perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
    }

    Ok(())
}

#[cfg(windows)]
fn set_file_perms(_dest_path: &Path, _src_path: &Path) -> Result<()> {
    Ok(())
}

#[derive(Debug)]
pub struct TarPackage<'a>(DirectoryPackage, temp::Dir<'a>);

impl<'a> TarPackage<'a> {
    pub fn new<R: Read>(stream: R, temp_cfg: &'a temp::Cfg) -> Result<Self> {
        let temp_dir = try!(temp_cfg.new_directory());
        let mut archive = tar::Archive::new(stream);
        // The rust-installer packages unpack to a directory called
        // $pkgname-$version-$target. Skip that directory when
        // unpacking.
        try!(unpack_without_first_dir(&mut archive, &*temp_dir));

        Ok(TarPackage(try!(DirectoryPackage::new(temp_dir.to_owned())), temp_dir))
    }
}

fn unpack_without_first_dir<R: Read>(archive: &mut tar::Archive<R>, path: &Path) -> Result<()> {
    let entries = try!(archive.entries().chain_err(|| ErrorKind::ExtractingPackage));
    for entry in entries {
        let mut entry = try!(entry.chain_err(|| ErrorKind::ExtractingPackage));
        let relpath = {
            let path = entry.path();
            let path = try!(path.chain_err(|| ErrorKind::ExtractingPackage));
            path.into_owned()
        };
        let mut components = relpath.components();
        // Throw away the first path component
        components.next();
        let full_path = path.join(&components.as_path());
        try!(entry.unpack(&full_path).chain_err(|| ErrorKind::ExtractingPackage));
    }

    Ok(())
}

impl<'a> Package for TarPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(&self,
                   target: &Components,
                   component: &str,
                   short_name: Option<&str>,
                   tx: Transaction<'b>)
                   -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}

#[derive(Debug)]
pub struct TarGzPackage<'a>(TarPackage<'a>);

impl<'a> TarGzPackage<'a> {
    pub fn new<R: Read>(stream: R, temp_cfg: &'a temp::Cfg) -> Result<Self> {
        let stream = try!(flate2::read::GzDecoder::new(stream).chain_err(|| ErrorKind::ExtractingPackage));

        Ok(TarGzPackage(try!(TarPackage::new(stream, temp_cfg))))
    }
    pub fn new_file(path: &Path, temp_cfg: &'a temp::Cfg) -> Result<Self> {
        let file = try!(File::open(path).chain_err(|| ErrorKind::ExtractingPackage));
        Self::new(file, temp_cfg)
    }
}

impl<'a> Package for TarGzPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(&self,
                   target: &Components,
                   component: &str,
                   short_name: Option<&str>,
                   tx: Transaction<'b>)
                   -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}
<commit_msg>Auto merge of #1098 - ranma42:safe-untar, r=brson<commit_after>//! An interpreter for the rust-installer package format.  Responsible
//! for installing from a directory or tarball to an installation
//! prefix, represented by a `Components` instance.

extern crate tar;
extern crate flate2;

use component::components::*;
use component::transaction::*;

use errors::*;
use rustup_utils::utils;
use temp;

use std::path::{Path, PathBuf};
use std::collections::HashSet;
use std::fmt;
use std::io::Read;
use std::fs::File;

/// The current metadata revision used by rust-installer
pub const INSTALLER_VERSION: &'static str = "3";
pub const VERSION_FILE: &'static str = "rust-installer-version";

pub trait Package: fmt::Debug {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool;
    fn install<'a>(&self,
                   target: &Components,
                   component: &str,
                   short_name: Option<&str>,
                   tx: Transaction<'a>)
                   -> Result<Transaction<'a>>;
    fn components(&self) -> Vec<String>;
}

#[derive(Debug)]
pub struct DirectoryPackage {
    path: PathBuf,
    components: HashSet<String>,
}

impl DirectoryPackage {
    pub fn new(path: PathBuf) -> Result<Self> {
        try!(validate_installer_version(&path));

        let content = try!(utils::read_file("package components", &path.join("components")));
        let components = content.lines().map(|l| l.to_owned()).collect();
        Ok(DirectoryPackage {
            path: path,
            components: components,
        })
    }
}

fn validate_installer_version(path: &Path) -> Result<()> {
    let file = try!(utils::read_file("installer version", &path.join(VERSION_FILE)));
    let v = file.trim();
    if v == INSTALLER_VERSION {
        Ok(())
    } else {
        Err(ErrorKind::BadInstallerVersion(v.to_owned()).into())
    }
}

impl Package for DirectoryPackage {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.components.contains(component) ||
        if let Some(n) = short_name {
            self.components.contains(n)
        } else {
            false
        }
    }
    fn install<'a>(&self,
                   target: &Components,
                   name: &str,
                   short_name: Option<&str>,
                   tx: Transaction<'a>)
                   -> Result<Transaction<'a>> {
        let actual_name = if self.components.contains(name) {
            name
        } else if let Some(n) = short_name {
            n
        } else {
            name
        };

        let root = self.path.join(actual_name);

        let manifest = try!(utils::read_file("package manifest", &root.join("manifest.in")));
        let mut builder = target.add(name, tx);

        for l in manifest.lines() {
            let part = try!(ComponentPart::decode(l)
                            .ok_or_else(|| ErrorKind::CorruptComponent(name.to_owned())));

            let path = part.1;
            let src_path = root.join(&path);

            match &*part.0 {
                "file" => try!(builder.copy_file(path.clone(), &src_path)),
                "dir" => try!(builder.copy_dir(path.clone(), &src_path)),
                _ => return Err(ErrorKind::CorruptComponent(name.to_owned()).into()),
            }

            try!(set_file_perms(&target.prefix().path().join(path), &src_path));
        }

        let tx = try!(builder.finish());

        Ok(tx)
    }

    fn components(&self) -> Vec<String> {
        self.components.iter().cloned().collect()
    }
}

// On Unix we need to set up the file permissions correctly so
// binaries are executable and directories readable. This shouldn't be
// necessary: the source files *should* have the right permissions,
// but due to rust-lang/rust#25479 they don't.
#[cfg(unix)]
fn set_file_perms(dest_path: &Path, src_path: &Path) -> Result<()> {
    use std::fs;
    use std::os::unix::fs::PermissionsExt;
    use walkdir::WalkDir;

    // By convention, anything in the bin/ directory of the package is a binary
    let is_bin = if let Some(p) = src_path.parent() {
        p.ends_with("bin")
    } else {
        false
    };

    let is_dir = utils::is_directory(dest_path);

    if is_dir {
        // Walk the directory setting everything
        for entry in WalkDir::new(dest_path) {
            let entry = try!(entry.chain_err(|| ErrorKind::ComponentDirPermissionsFailed));
            let meta = try!(entry.metadata().chain_err(|| ErrorKind::ComponentDirPermissionsFailed));
            if meta.is_dir() {
                let mut perm = meta.permissions();
                perm.set_mode(0o755);
                try!(fs::set_permissions(entry.path(), perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
            } else {
                let mut perm = meta.permissions();
                perm.set_mode(0o644);
                try!(fs::set_permissions(entry.path(), perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
            }
        }
    } else if is_bin {
        let mut perm = try!(fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed))
                           .permissions();
        perm.set_mode(0o755);
        try!(fs::set_permissions(dest_path, perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
    } else {
        let mut perm = try!(fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed))
                           .permissions();
        perm.set_mode(0o644);
        try!(fs::set_permissions(dest_path, perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
    }

    Ok(())
}

#[cfg(windows)]
fn set_file_perms(_dest_path: &Path, _src_path: &Path) -> Result<()> {
    Ok(())
}

#[derive(Debug)]
pub struct TarPackage<'a>(DirectoryPackage, temp::Dir<'a>);

impl<'a> TarPackage<'a> {
    pub fn new<R: Read>(stream: R, temp_cfg: &'a temp::Cfg) -> Result<Self> {
        let temp_dir = try!(temp_cfg.new_directory());
        let mut archive = tar::Archive::new(stream);
        // The rust-installer packages unpack to a directory called
        // $pkgname-$version-$target. Skip that directory when
        // unpacking.
        try!(unpack_without_first_dir(&mut archive, &*temp_dir));

        Ok(TarPackage(try!(DirectoryPackage::new(temp_dir.to_owned())), temp_dir))
    }
}

fn unpack_without_first_dir<R: Read>(archive: &mut tar::Archive<R>, path: &Path) -> Result<()> {
    let entries = try!(archive.entries().chain_err(|| ErrorKind::ExtractingPackage));
    for entry in entries {
        let mut entry = try!(entry.chain_err(|| ErrorKind::ExtractingPackage));
        let relpath = {
            let path = entry.path();
            let path = try!(path.chain_err(|| ErrorKind::ExtractingPackage));
            path.into_owned()
        };
        let mut components = relpath.components();
        // Throw away the first path component
        components.next();
        let full_path = path.join(&components.as_path());

        // Create the full path to the entry if it does not exist already
        match full_path.parent() {
            Some(parent) if !parent.exists() =>
                try!(::std::fs::create_dir_all(&parent).chain_err(|| ErrorKind::ExtractingPackage)),
            _ => (),
        };

        try!(entry.unpack(&full_path).chain_err(|| ErrorKind::ExtractingPackage));
    }

    Ok(())
}

impl<'a> Package for TarPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(&self,
                   target: &Components,
                   component: &str,
                   short_name: Option<&str>,
                   tx: Transaction<'b>)
                   -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}

#[derive(Debug)]
pub struct TarGzPackage<'a>(TarPackage<'a>);

impl<'a> TarGzPackage<'a> {
    pub fn new<R: Read>(stream: R, temp_cfg: &'a temp::Cfg) -> Result<Self> {
        let stream = try!(flate2::read::GzDecoder::new(stream).chain_err(|| ErrorKind::ExtractingPackage));

        Ok(TarGzPackage(try!(TarPackage::new(stream, temp_cfg))))
    }
    pub fn new_file(path: &Path, temp_cfg: &'a temp::Cfg) -> Result<Self> {
        let file = try!(File::open(path).chain_err(|| ErrorKind::ExtractingPackage));
        Self::new(file, temp_cfg)
    }
}

impl<'a> Package for TarGzPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(&self,
                   target: &Components,
                   component: &str,
                   short_name: Option<&str>,
                   tx: Transaction<'b>)
                   -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}
<|endoftext|>


<commit_before>use core::{mem, str};

use paging::{ActivePageTable, VirtualAddress};

/// Get a stack trace
//TODO: Check for stack being mapped before dereferencing
#[inline(never)]
pub unsafe fn stack_trace() {
    let mut rbp: usize;
    asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");

    println!("TRACE: {:>016X}", rbp);
    //Maximum 64 frames
    let active_table = ActivePageTable::new();
    for _frame in 0..64 {
        if let Some(rip_rbp) = rbp.checked_add(mem::size_of::<usize>()) {
            if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() {
                let rip = *(rip_rbp as *const usize);
                if rip == 0 {
                    println!(" {:>016X}: EMPTY RETURN", rbp);
                    break;
                }
                println!("  {:>016X}: {:>016X}", rbp, rip);
                rbp = *(rbp as *const usize);
                symbol_trace(rip);
            } else {
                println!("  {:>016X}: GUARD PAGE", rbp);
                break;
            }
        } else {
            println!("  {:>016X}: RBP OVERFLOW", rbp);
        }
    }
}

/// Get a symbol
//TODO: Do not create Elf object for every symbol lookup
#[inline(never)]
pub unsafe fn symbol_trace(addr: usize) {
    use core::slice;
    use core::sync::atomic::Ordering;

    use elf::Elf;
    use start::{KERNEL_BASE, KERNEL_SIZE};

    let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + ::KERNEL_OFFSET) as *const u8;
    let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
    if let Ok(elf) = Elf::from(kernel_slice) {
        let mut strtab_opt = None;
        for section in elf.sections() {
            if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB {
                strtab_opt = Some(section);
                break;
            }
        }

        if let Some(symbols) = elf.symbols() {
            for sym in symbols {
                if addr >= sym.st_value as usize && addr < (sym.st_value + sym.st_size) as usize {
                    println!("    {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize);

                    if let Some(strtab) = strtab_opt {
                        let start = strtab.sh_offset as usize + sym.st_name as usize;
                        let mut end = start;
                        while end < elf.data.len() {
                            let b = elf.data[end];
                            end += 1;
                            if b == 0 {
                                break;
                            }
                        }

                        if end > start {
                            let sym_name = str::from_utf8_unchecked(&elf.data[start .. end]);
                            println!("    {}", sym_name);
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>Demangle symbols<commit_after>use core::{mem, str};
use goblin::elf::sym;

use paging::{ActivePageTable, VirtualAddress};

/// Get a stack trace
//TODO: Check for stack being mapped before dereferencing
#[inline(never)]
pub unsafe fn stack_trace() {
    let mut rbp: usize;
    asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");

    println!("TRACE: {:>016X}", rbp);
    //Maximum 64 frames
    let active_table = ActivePageTable::new();
    for _frame in 0..64 {
        if let Some(rip_rbp) = rbp.checked_add(mem::size_of::<usize>()) {
            if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() {
                let rip = *(rip_rbp as *const usize);
                if rip == 0 {
                    println!(" {:>016X}: EMPTY RETURN", rbp);
                    break;
                }
                println!("  {:>016X}: {:>016X}", rbp, rip);
                rbp = *(rbp as *const usize);
                symbol_trace(rip);
            } else {
                println!("  {:>016X}: GUARD PAGE", rbp);
                break;
            }
        } else {
            println!("  {:>016X}: RBP OVERFLOW", rbp);
        }
    }
}

/// Get a symbol
//TODO: Do not create Elf object for every symbol lookup
#[inline(never)]
pub unsafe fn symbol_trace(addr: usize) {
    use core::slice;
    use core::sync::atomic::Ordering;

    use elf::Elf;
    use start::{KERNEL_BASE, KERNEL_SIZE};

    let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + ::KERNEL_OFFSET) as *const u8;
    let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
    if let Ok(elf) = Elf::from(kernel_slice) {
        let mut strtab_opt = None;
        for section in elf.sections() {
            if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB {
                strtab_opt = Some(section);
                break;
            }
        }

        if let Some(symbols) = elf.symbols() {
            for sym in symbols {
                if sym::st_type(sym.st_info) == sym::STT_FUNC
                && addr >= sym.st_value as usize
                && addr < (sym.st_value + sym.st_size) as usize
                {
                    println!("    {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize);

                    if let Some(strtab) = strtab_opt {
                        let start = strtab.sh_offset as usize + sym.st_name as usize;
                        let mut end = start;
                        while end < elf.data.len() {
                            let b = elf.data[end];
                            end += 1;
                            if b == 0 {
                                break;
                            }
                        }

                        if end > start {
                            let sym_name = &elf.data[start .. end];

                            print!("    ");

                            if sym_name.starts_with(b"_ZN") {
                                // Skip _ZN
                                let mut i = 3;
                                let mut first = true;
                                while i < sym_name.len() {
                                    // E is the end character
                                    if sym_name[i] == b'E' {
                                        break;
                                    }

                                    // Parse length string
                                    let mut len = 0;
                                    while i < sym_name.len() {
                                        let b = sym_name[i];
                                        if b >= b'0' && b <= b'9' {
                                            i += 1;
                                            len *= 10;
                                            len += (b - b'0') as usize;
                                        } else {
                                            break;
                                        }
                                    }

                                    // Print namespace seperator, if required
                                    if first {
                                        first = false;
                                    } else {
                                        print!("::");
                                    }

                                    // Print name string
                                    let end = i + len;
                                    while i < sym_name.len() && i < end {
                                        print!("{}", sym_name[i] as char);
                                        i += 1;
                                    }
                                }
                            } else {
                                for &b in sym_name.iter() {
                                    print!("{}", b as char);
                                }
                            }

                            println!("");
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>put a limit to the iterations over one event<commit_after><|endoftext|>


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

#[feature(managed_boxes)];

trait noisy {
  fn speak(&mut self);
}

struct cat {
  meows: uint,
  how_hungry: int,
  name: ~str,
}

impl noisy for cat {
  fn speak(&mut self) { self.meow(); }
}

impl cat {
  pub fn eat(&mut self) -> bool {
    if self.how_hungry > 0 {
        println!("OM NOM NOM");
        self.how_hungry -= 2;
        return true;
    }
    else {
        println!("Not hungry!");
        return false;
    }
  }
}

impl cat {
    fn meow(&mut self) {
      println!("Meow");
      self.meows += 1u;
      if self.meows % 5u == 0u {
          self.how_hungry += 1;
      }
    }
}

fn cat(in_x : uint, in_y : int, in_name: ~str) -> cat {
    cat {
        meows: in_x,
        how_hungry: in_y,
        name: in_name
    }
}

pub fn main() {
    let mut nyan = cat(0u, 2, ~"nyan");
    let mut nyan: &mut noisy = &mut nyan;
    nyan.speak();
}
<commit_msg>Ignore another test that fails mysteriously on BSD<commit_after>// Copyright 2012 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.

// ignore-test FIXME fails on BSD

#[feature(managed_boxes)];

trait noisy {
  fn speak(&mut self);
}

struct cat {
  meows: uint,
  how_hungry: int,
  name: ~str,
}

impl noisy for cat {
  fn speak(&mut self) { self.meow(); }
}

impl cat {
  pub fn eat(&mut self) -> bool {
    if self.how_hungry > 0 {
        println!("OM NOM NOM");
        self.how_hungry -= 2;
        return true;
    }
    else {
        println!("Not hungry!");
        return false;
    }
  }
}

impl cat {
    fn meow(&mut self) {
      println!("Meow");
      self.meows += 1u;
      if self.meows % 5u == 0u {
          self.how_hungry += 1;
      }
    }
}

fn cat(in_x : uint, in_y : int, in_name: ~str) -> cat {
    cat {
        meows: in_x,
        how_hungry: in_y,
        name: in_name
    }
}

pub fn main() {
    let mut nyan = cat(0u, 2, ~"nyan");
    let mut nyan: &mut noisy = &mut nyan;
    nyan.speak();
}
<|endoftext|>


<commit_before>use walkdir::WalkDir;
use std::path::PathBuf;
use std::{env, fs};

fn main() {
    // The src directory (we are in src/tools/error_index_generator)
    // Note that we could skip one of the .. but this ensures we at least loosely find the right
    // directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let dest = out_dir.join("error_codes.rs");

    let error_codes_path = "../../../src/librustc_error_codes/error_codes.rs";

    println!("cargo:rerun-if-changed={}", error_codes_path);
    let file = fs::read_to_string(error_codes_path).unwrap()
                  .replace("crate::register_diagnostics!", "register_diagnostics!")
                  .replace(": include_str!(\"./error_codes/", ": include_str!(\"./");
    let contents = format!("(|| {{\n{}\n}})()", file);
    fs::write(&out_dir.join("all_error_codes.rs"), &contents).unwrap();

    // We copy the md files as well to the target directory.
    for entry in WalkDir::new("../../../src/librustc_error_codes/error_codes") {
        let entry = entry.unwrap();
        match entry.path().extension() {
            Some(s) if s == "md" => {}
            _ => continue,
        }
        println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap());
        let md_content = fs::read_to_string(entry.path()).unwrap();
        fs::write(&out_dir.join(entry.file_name()), &md_content).unwrap();
    }

    let mut all = String::new();
    all.push_str(r###"
fn register_all() -> Vec<(&'static str, Option<&'static str>)> {
    let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new();
    macro_rules! register_diagnostics {
        ($($ecode:ident: $message:expr,)*) => (
            register_diagnostics!{$($ecode:$message,)* ;}
        );

        ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
            $(
                {long_codes.extend([
                    (stringify!($ecode), Some($message)),
                ].iter());}
            )*
            $(
                {long_codes.extend([
                    stringify!($code),
                ].iter().cloned().map(|s| (s, None)).collect::<Vec<_>>());}
            )*
        )
    }
"###);
    all.push_str(r#"include!(concat!(env!("OUT_DIR"), "/all_error_codes.rs"));"#);
    all.push_str("\nlong_codes\n");
    all.push_str("}\n");

    fs::write(&dest, all).unwrap();
}
<commit_msg>Remove useless line for error index generation<commit_after>use walkdir::WalkDir;
use std::path::PathBuf;
use std::{env, fs};

fn main() {
    // The src directory (we are in src/tools/error_index_generator)
    // Note that we could skip one of the .. but this ensures we at least loosely find the right
    // directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let dest = out_dir.join("error_codes.rs");

    let error_codes_path = "../../../src/librustc_error_codes/error_codes.rs";

    println!("cargo:rerun-if-changed={}", error_codes_path);
    let file = fs::read_to_string(error_codes_path).unwrap()
                  .replace(": include_str!(\"./error_codes/", ": include_str!(\"./");
    let contents = format!("(|| {{\n{}\n}})()", file);
    fs::write(&out_dir.join("all_error_codes.rs"), &contents).unwrap();

    // We copy the md files as well to the target directory.
    for entry in WalkDir::new("../../../src/librustc_error_codes/error_codes") {
        let entry = entry.unwrap();
        match entry.path().extension() {
            Some(s) if s == "md" => {}
            _ => continue,
        }
        println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap());
        let md_content = fs::read_to_string(entry.path()).unwrap();
        fs::write(&out_dir.join(entry.file_name()), &md_content).unwrap();
    }

    let mut all = String::new();
    all.push_str(r###"
fn register_all() -> Vec<(&'static str, Option<&'static str>)> {
    let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new();
    macro_rules! register_diagnostics {
        ($($ecode:ident: $message:expr,)*) => (
            register_diagnostics!{$($ecode:$message,)* ;}
        );

        ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
            $(
                {long_codes.extend([
                    (stringify!($ecode), Some($message)),
                ].iter());}
            )*
            $(
                {long_codes.extend([
                    stringify!($code),
                ].iter().cloned().map(|s| (s, None)).collect::<Vec<_>>());}
            )*
        )
    }
"###);
    all.push_str(r#"include!(concat!(env!("OUT_DIR"), "/all_error_codes.rs"));"#);
    all.push_str("\nlong_codes\n");
    all.push_str("}\n");

    fs::write(&dest, all).unwrap();
}
<|endoftext|>


<commit_before><commit_msg>Add pass-through impl's for I/O traits on &mut references<commit_after><|endoftext|>