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

use ty::AdtKind;
use ty::layout::{Align, Size};

use rustc_data_structures::fx::{FxHashSet};

use std::cmp::{self, Ordering};

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct VariantInfo {
    pub name: Option<String>,
    pub kind: SizeKind,
    pub size: u64,
    pub align: u64,
    pub fields: Vec<FieldInfo>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum SizeKind {
    Exact,
    Min,
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct FieldInfo {
    pub name: String,
    pub offset: u64,
    pub size: u64,
    pub align: u64,
}

impl From<AdtKind> for DataTypeKind {
    fn from(kind: AdtKind) -> Self {
        match kind {
            AdtKind::Struct => DataTypeKind::Struct,
            AdtKind::Enum => DataTypeKind::Enum,
            AdtKind::Union => DataTypeKind::Union,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum DataTypeKind {
    Struct,
    Union,
    Enum,
    Closure,
}

#[derive(PartialEq, Eq, Hash, Debug)]
pub struct TypeSizeInfo {
    pub kind: DataTypeKind,
    pub type_description: String,
    pub align: u64,
    pub overall_size: u64,
    pub opt_discr_size: Option<u64>,
    pub variants: Vec<VariantInfo>,
}

#[derive(PartialEq, Eq, Debug)]
pub struct CodeStats {
    type_sizes: FxHashSet<TypeSizeInfo>,
}

impl CodeStats {
    pub fn new() -> Self { CodeStats { type_sizes: FxHashSet() } }

    pub fn record_type_size<S: ToString>(&mut self,
                                         kind: DataTypeKind,
                                         type_desc: S,
                                         align: Align,
                                         overall_size: Size,
                                         opt_discr_size: Option<Size>,
                                         variants: Vec<VariantInfo>) {
        let info = TypeSizeInfo {
            kind,
            type_description: type_desc.to_string(),
            align: align.abi(),
            overall_size: overall_size.bytes(),
            opt_discr_size: opt_discr_size.map(|s| s.bytes()),
            variants,
        };
        self.type_sizes.insert(info);
    }

    pub fn print_type_sizes(&self) {
        let mut sorted: Vec<_> = self.type_sizes.iter().collect();

        // Primary sort: large-to-small.
        // Secondary sort: description (dictionary order)
        sorted.sort_by(|info1, info2| {
            // (reversing cmp order to get large-to-small ordering)
            match info2.overall_size.cmp(&info1.overall_size) {
                Ordering::Equal => info1.type_description.cmp(&info2.type_description),
                other => other,
            }
        });

        for info in &sorted {
            println!("print-type-size type: `{}`: {} bytes, alignment: {} bytes",
                     info.type_description, info.overall_size, info.align);
            let indent = "    ";

            let discr_size = if let Some(discr_size) = info.opt_discr_size {
                println!("print-type-size {}discriminant: {} bytes",
                         indent, discr_size);
                discr_size
            } else {
                0
            };

            // We start this at discr_size (rather than 0) because
            // things like C-enums do not have variants but we still
            // want the max_variant_size at the end of the loop below
            // to reflect the presence of the discriminant.
            let mut max_variant_size = discr_size;

            let struct_like = match info.kind {
                DataTypeKind::Struct | DataTypeKind::Closure => true,
                DataTypeKind::Enum | DataTypeKind::Union => false,
            };
            for (i, variant_info) in info.variants.iter().enumerate() {
                let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;
                let indent = if !struct_like {
                    let name = match name.as_ref() {
                        Some(name) => format!("{}", name),
                        None => format!("{}", i),
                    };
                    println!("print-type-size {}variant `{}`: {} bytes",
                             indent, name, size - discr_size);
                    "        "
                } else {
                    assert!(i < 1);
                    "    "
                };
                max_variant_size = cmp::max(max_variant_size, size);

                let mut min_offset = discr_size;

                // We want to print fields by increasing offset.
                let mut fields = fields.clone();
                fields.sort_by_key(|f| f.offset);

                for field in fields.iter() {
                    let FieldInfo { ref name, offset, size, align } = *field;

                    // Include field alignment in output only if it caused padding injection
                    if min_offset != offset {
                        let pad = offset - min_offset;
                        println!("print-type-size {}padding: {} bytes",
                                 indent, pad);
                        println!("print-type-size {}field `.{}`: {} bytes, alignment: {} bytes",
                                 indent, name, size, align);
                    } else {
                        println!("print-type-size {}field `.{}`: {} bytes",
                                 indent, name, size);
                    }

                    min_offset = offset + size;
                }
            }

            assert!(max_variant_size <= info.overall_size,
                    "max_variant_size {} !<= {} overall_size",
                    max_variant_size, info.overall_size);
            if max_variant_size < info.overall_size {
                println!("print-type-size {}end padding: {} bytes",
                         indent, info.overall_size - max_variant_size);
            }
        }
    }
}
<commit_msg>avoid ICE when fields are not laid out in order<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ty::AdtKind;
use ty::layout::{Align, Size};

use rustc_data_structures::fx::{FxHashSet};

use std::cmp::{self, Ordering};

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct VariantInfo {
    pub name: Option<String>,
    pub kind: SizeKind,
    pub size: u64,
    pub align: u64,
    pub fields: Vec<FieldInfo>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum SizeKind {
    Exact,
    Min,
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct FieldInfo {
    pub name: String,
    pub offset: u64,
    pub size: u64,
    pub align: u64,
}

impl From<AdtKind> for DataTypeKind {
    fn from(kind: AdtKind) -> Self {
        match kind {
            AdtKind::Struct => DataTypeKind::Struct,
            AdtKind::Enum => DataTypeKind::Enum,
            AdtKind::Union => DataTypeKind::Union,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum DataTypeKind {
    Struct,
    Union,
    Enum,
    Closure,
}

#[derive(PartialEq, Eq, Hash, Debug)]
pub struct TypeSizeInfo {
    pub kind: DataTypeKind,
    pub type_description: String,
    pub align: u64,
    pub overall_size: u64,
    pub opt_discr_size: Option<u64>,
    pub variants: Vec<VariantInfo>,
}

#[derive(PartialEq, Eq, Debug)]
pub struct CodeStats {
    type_sizes: FxHashSet<TypeSizeInfo>,
}

impl CodeStats {
    pub fn new() -> Self { CodeStats { type_sizes: FxHashSet() } }

    pub fn record_type_size<S: ToString>(&mut self,
                                         kind: DataTypeKind,
                                         type_desc: S,
                                         align: Align,
                                         overall_size: Size,
                                         opt_discr_size: Option<Size>,
                                         variants: Vec<VariantInfo>) {
        let info = TypeSizeInfo {
            kind,
            type_description: type_desc.to_string(),
            align: align.abi(),
            overall_size: overall_size.bytes(),
            opt_discr_size: opt_discr_size.map(|s| s.bytes()),
            variants,
        };
        self.type_sizes.insert(info);
    }

    pub fn print_type_sizes(&self) {
        let mut sorted: Vec<_> = self.type_sizes.iter().collect();

        // Primary sort: large-to-small.
        // Secondary sort: description (dictionary order)
        sorted.sort_by(|info1, info2| {
            // (reversing cmp order to get large-to-small ordering)
            match info2.overall_size.cmp(&info1.overall_size) {
                Ordering::Equal => info1.type_description.cmp(&info2.type_description),
                other => other,
            }
        });

        for info in &sorted {
            println!("print-type-size type: `{}`: {} bytes, alignment: {} bytes",
                     info.type_description, info.overall_size, info.align);
            let indent = "    ";

            let discr_size = if let Some(discr_size) = info.opt_discr_size {
                println!("print-type-size {}discriminant: {} bytes",
                         indent, discr_size);
                discr_size
            } else {
                0
            };

            // We start this at discr_size (rather than 0) because
            // things like C-enums do not have variants but we still
            // want the max_variant_size at the end of the loop below
            // to reflect the presence of the discriminant.
            let mut max_variant_size = discr_size;

            let struct_like = match info.kind {
                DataTypeKind::Struct | DataTypeKind::Closure => true,
                DataTypeKind::Enum | DataTypeKind::Union => false,
            };
            for (i, variant_info) in info.variants.iter().enumerate() {
                let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;
                let indent = if !struct_like {
                    let name = match name.as_ref() {
                        Some(name) => format!("{}", name),
                        None => format!("{}", i),
                    };
                    println!("print-type-size {}variant `{}`: {} bytes",
                             indent, name, size - discr_size);
                    "        "
                } else {
                    assert!(i < 1);
                    "    "
                };
                max_variant_size = cmp::max(max_variant_size, size);

                let mut min_offset = discr_size;

                // We want to print fields by increasing offset.
                let mut fields = fields.clone();
                fields.sort_by_key(|f| f.offset);

                for field in fields.iter() {
                    let FieldInfo { ref name, offset, size, align } = *field;

                    // Include field alignment in output only if it caused padding injection
                    if min_offset != offset {
                        if offset > min_offset {
                            let pad = offset - min_offset;
                            println!("print-type-size {}padding: {} bytes",
                                     indent, pad);
                            println!("print-type-size {}field `.{}`: {} bytes, \
                                      alignment: {} bytes",
                                     indent, name, size, align);
                        } else {
                            println!("print-type-size {}field `.{}`: {} bytes, \
                                      offset: {} bytes, \
                                      alignment: {} bytes",
                                     indent, name, size, offset, align);
                        }
                    } else {
                        println!("print-type-size {}field `.{}`: {} bytes",
                                 indent, name, size);
                    }

                    min_offset = offset + size;
                }
            }

            assert!(max_variant_size <= info.overall_size,
                    "max_variant_size {} !<= {} overall_size",
                    max_variant_size, info.overall_size);
            if max_variant_size < info.overall_size {
                println!("print-type-size {}end padding: {} bytes",
                         indent, info.overall_size - max_variant_size);
            }
        }
    }
}
<|endoftext|>


<commit_before>use rustc::ty::{self, Ty, TypeAndMut};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::symbol::sym;

use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
    Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
};
use rustc::mir::CastKind;

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

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
    fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
        match ty.sty {
            ty::RawPtr(ty::TypeAndMut { ty, .. }) |
            ty::Ref(_, ty, _) => !self.type_is_sized(ty),
            ty::Adt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
            _ => false,
        }
    }

    pub fn cast(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        kind: CastKind,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        use rustc::mir::CastKind::*;
        match kind {
            Pointer(PointerCast::Unsize) => {
                self.unsize_into(src, dest)?;
            }

            Misc | Pointer(PointerCast::MutToConstPointer) => {
                let src = self.read_immediate(src)?;

                if self.type_is_fat_ptr(src.layout.ty) {
                    match (*src, self.type_is_fat_ptr(dest.layout.ty)) {
                        // pointers to extern types
                        (Immediate::Scalar(_),_) |
                        // slices and trait objects to other slices/trait objects
                        (Immediate::ScalarPair(..), true) => {
                            // No change to immediate
                            self.write_immediate(*src, dest)?;
                        }
                        // slices and trait objects to thin pointers (dropping the metadata)
                        (Immediate::ScalarPair(data, _), false) => {
                            self.write_scalar(data, dest)?;
                        }
                    }
                } else {
                    match src.layout.variants {
                        layout::Variants::Single { index } => {
                            if let Some(discr) =
                                src.layout.ty.discriminant_for_variant(*self.tcx, index)
                            {
                                // Cast from a univariant enum
                                assert!(src.layout.is_zst());
                                return self.write_scalar(
                                    Scalar::from_uint(discr.val, dest.layout.size),
                                    dest);
                            }
                        }
                        layout::Variants::Multiple { .. } => {},
                    }

                    let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?;
                    self.write_scalar(dest_val, dest)?;
                }
            }

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::FnDef(def_id, substs) => {
                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance: InterpResult<'tcx, _> = ty::Instance::resolve(
                            *self.tcx,
                            self.param_env,
                            def_id,
                            substs,
                        ).ok_or_else(|| InterpError::TooGeneric.into());
                        let fn_ptr = self.memory.create_fn_alloc(instance?);
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

            Pointer(PointerCast::UnsafeFnPointer) => {
                let src = self.read_immediate(src)?;
                match dest.layout.ty.sty {
                    ty::FnPtr(_) => {
                        // No change to value
                        self.write_immediate(*src, dest)?;
                    }
                    _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty),
                }
            }

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::Closure(def_id, substs) => {
                        let substs = self.subst_and_normalize_erasing_regions(substs)?;
                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(instance);
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

    fn cast_scalar(
        &self,
        val: Scalar<M::PointerTag>,
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        use rustc::ty::TyKind::*;
        trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);

        match src_layout.ty.sty {
            // Floating point
            Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty),
            Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty),
            // Integer(-like), including fn ptr casts and casts from enums that
            // are represented as integers (this excludes univariant enums, which
            // are handled in `cast` directly).
            _ => {
                assert!(
                    src_layout.ty.is_bool()       || src_layout.ty.is_char()     ||
                    src_layout.ty.is_enum()       || src_layout.ty.is_integral() ||
                    src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr()   ||
                    src_layout.ty.is_region_ptr(),
                    "Unexpected cast from type {:?}", src_layout.ty
                );
                match val.to_bits_or_ptr(src_layout.size, self) {
                    Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
                    Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
                }
            }
        }
    }

    fn cast_from_int(
        &self,
        v: u128, // raw bits
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        // Let's make sure v is sign-extended *if* it has a signed type.
        let signed = src_layout.abi.is_signed();
        let v = if signed {
            self.sign_extend(v, src_layout)
        } else {
            v
        };
        trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
        use rustc::ty::TyKind::*;
        match dest_layout.ty.sty {
            Int(_) | Uint(_) | RawPtr(_) => {
                let v = self.truncate(v, dest_layout);
                Ok(Scalar::from_uint(v, dest_layout.size))
            }

            Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
                Single::from_i128(v as i128).value
            )),
            Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
                Double::from_i128(v as i128).value
            )),
            Float(FloatTy::F32) => Ok(Scalar::from_f32(
                Single::from_u128(v).value
            )),
            Float(FloatTy::F64) => Ok(Scalar::from_f64(
                Double::from_u128(v).value
            )),

            Char => {
                // `u8` to `char` cast
                debug_assert_eq!(v as u8 as u128, v);
                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
            },

            // Casts to bool are not permitted by rustc, no need to handle them here.
            _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
        }
    }

    fn cast_from_float<F>(
        &self,
        f: F,
        dest_ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
    {
        use rustc::ty::TyKind::*;
        match dest_ty.sty {
            // float -> uint
            Uint(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_u128(width).value;
                // This should already fit the bit width
                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
            },
            // float -> int
            Int(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_i128(width).value;
                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
            },
            // float -> f32
            Float(FloatTy::F32) =>
                Ok(Scalar::from_f32(f.convert(&mut false).value)),
            // float -> f64
            Float(FloatTy::F64) =>
                Ok(Scalar::from_f64(f.convert(&mut false).value)),
            // That's it.
            _ => bug!("invalid float to {:?} cast", dest_ty),
        }
    }

    fn cast_from_ptr(
        &self,
        ptr: Pointer<M::PointerTag>,
        ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        use rustc::ty::TyKind::*;

        let size = match ty.sty {
            // Casting to a reference or fn pointer is not permitted by rustc,
            // no need to support it here.
            RawPtr(_) => return Ok(ptr.into()),
            Int(IntTy::Isize) | Uint(UintTy::Usize) => {
                let size = self.memory.pointer_size();
                if let Ok(bits) = self.force_bits(Scalar::Ptr(ptr), size) {
                    return Ok(Scalar::from_uint(bits, size));
                }
                return Ok(ptr.into());
            }
            // If the target type is a sized integer, we need the its size to perform the pointer cast
            Int(i) => i.bit_width().unwrap(),
            Uint(i) => i.bit_width().unwrap(),
            // Casting to any other type is not implemented
            _ => return err!(Unimplemented(format!("ptr to {:?} cast", ty))),
        };

        let size = Size::from_bits(size as u64);

        if let Ok(bits) = self.force_bits(Scalar::Ptr(ptr), size) {
            Ok(Scalar::from_uint(bits, size))
        } else {
            err!(ReadPointerAsBytes)
        }
    }

    fn unsize_into_ptr(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
        // The pointee types
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
    ) -> InterpResult<'tcx> {
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::Array(_, length), &ty::Slice(_)) => {
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                // u64 cast is from usize to u64, which is always good
                let val = Immediate::new_slice(
                    ptr,
                    length.unwrap_usize(self.tcx.tcx),
                    self,
                );
                self.write_immediate(val, dest)
            }
            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                let val = self.read_immediate(src)?;
                self.write_immediate(*val, dest)
            }
            (_, &ty::Dynamic(ref data, _)) => {
                // Initial cast from sized to dyn trait
                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                let val = Immediate::new_dyn_trait(ptr, vtable);
                self.write_immediate(val, dest)
            }

            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty),
        }
    }

    fn unsize_into(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        trace!("Unsizing {:?} into {:?}", src, dest);
        match (&src.layout.ty.sty, &dest.layout.ty.sty) {
            (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
            (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
            (&ty::RawPtr(TypeAndMut { ty: s, .. }),
             &ty::RawPtr(TypeAndMut { ty: d, .. })) => {
                self.unsize_into_ptr(src, dest, s, d)
            }
            (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                assert_eq!(def_a, def_b);
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout);
                    }
                    return self.unsize_into_ptr(
                        src,
                        dest,
                        src.layout.ty.boxed_ty(),
                        dest.layout.ty.boxed_ty(),
                    );
                }

                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
                for i in 0..src.layout.fields.count() {
                    let dst_field = self.place_field(dest, i as u64)?;
                    if dst_field.layout.is_zst() {
                        continue;
                    }
                    let src_field = self.operand_field(src, i as u64)?;
                    if src_field.layout.ty == dst_field.layout.ty {
                        self.copy_op(src_field, dst_field)?;
                    } else {
                        self.unsize_into(src_field, dst_field)?;
                    }
                }
                Ok(())
            }
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
                    src.layout,
                    dest.layout
                )
            }
        }
    }
}
<commit_msg>Reorganize code for readabilty and fixed problem with type sizes<commit_after>use rustc::ty::{self, Ty, TypeAndMut};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::symbol::sym;

use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
    Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
};
use rustc::mir::CastKind;

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

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
    fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
        match ty.sty {
            ty::RawPtr(ty::TypeAndMut { ty, .. }) |
            ty::Ref(_, ty, _) => !self.type_is_sized(ty),
            ty::Adt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
            _ => false,
        }
    }

    pub fn cast(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        kind: CastKind,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        use rustc::mir::CastKind::*;
        match kind {
            Pointer(PointerCast::Unsize) => {
                self.unsize_into(src, dest)?;
            }

            Misc | Pointer(PointerCast::MutToConstPointer) => {
                let src = self.read_immediate(src)?;

                if self.type_is_fat_ptr(src.layout.ty) {
                    match (*src, self.type_is_fat_ptr(dest.layout.ty)) {
                        // pointers to extern types
                        (Immediate::Scalar(_),_) |
                        // slices and trait objects to other slices/trait objects
                        (Immediate::ScalarPair(..), true) => {
                            // No change to immediate
                            self.write_immediate(*src, dest)?;
                        }
                        // slices and trait objects to thin pointers (dropping the metadata)
                        (Immediate::ScalarPair(data, _), false) => {
                            self.write_scalar(data, dest)?;
                        }
                    }
                } else {
                    match src.layout.variants {
                        layout::Variants::Single { index } => {
                            if let Some(discr) =
                                src.layout.ty.discriminant_for_variant(*self.tcx, index)
                            {
                                // Cast from a univariant enum
                                assert!(src.layout.is_zst());
                                return self.write_scalar(
                                    Scalar::from_uint(discr.val, dest.layout.size),
                                    dest);
                            }
                        }
                        layout::Variants::Multiple { .. } => {},
                    }

                    let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?;
                    self.write_scalar(dest_val, dest)?;
                }
            }

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::FnDef(def_id, substs) => {
                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance: InterpResult<'tcx, _> = ty::Instance::resolve(
                            *self.tcx,
                            self.param_env,
                            def_id,
                            substs,
                        ).ok_or_else(|| InterpError::TooGeneric.into());
                        let fn_ptr = self.memory.create_fn_alloc(instance?);
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

            Pointer(PointerCast::UnsafeFnPointer) => {
                let src = self.read_immediate(src)?;
                match dest.layout.ty.sty {
                    ty::FnPtr(_) => {
                        // No change to value
                        self.write_immediate(*src, dest)?;
                    }
                    _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty),
                }
            }

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::Closure(def_id, substs) => {
                        let substs = self.subst_and_normalize_erasing_regions(substs)?;
                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(instance);
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

    fn cast_scalar(
        &self,
        val: Scalar<M::PointerTag>,
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        use rustc::ty::TyKind::*;
        trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);

        match src_layout.ty.sty {
            // Floating point
            Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty),
            Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty),
            // Integer(-like), including fn ptr casts and casts from enums that
            // are represented as integers (this excludes univariant enums, which
            // are handled in `cast` directly).
            _ => {
                assert!(
                    src_layout.ty.is_bool()       || src_layout.ty.is_char()     ||
                    src_layout.ty.is_enum()       || src_layout.ty.is_integral() ||
                    src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr()   ||
                    src_layout.ty.is_region_ptr(),
                    "Unexpected cast from type {:?}", src_layout.ty
                );
                match val.to_bits_or_ptr(src_layout.size, self) {
                    Err(ptr) => self.cast_from_ptr(ptr, src_layout, dest_layout),
                    Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
                }
            }
        }
    }

    fn cast_from_int(
        &self,
        v: u128, // raw bits
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        // Let's make sure v is sign-extended *if* it has a signed type.
        let signed = src_layout.abi.is_signed();
        let v = if signed {
            self.sign_extend(v, src_layout)
        } else {
            v
        };
        trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
        use rustc::ty::TyKind::*;
        match dest_layout.ty.sty {
            Int(_) | Uint(_) | RawPtr(_) => {
                let v = self.truncate(v, dest_layout);
                Ok(Scalar::from_uint(v, dest_layout.size))
            }

            Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
                Single::from_i128(v as i128).value
            )),
            Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
                Double::from_i128(v as i128).value
            )),
            Float(FloatTy::F32) => Ok(Scalar::from_f32(
                Single::from_u128(v).value
            )),
            Float(FloatTy::F64) => Ok(Scalar::from_f64(
                Double::from_u128(v).value
            )),

            Char => {
                // `u8` to `char` cast
                debug_assert_eq!(v as u8 as u128, v);
                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
            },

            // Casts to bool are not permitted by rustc, no need to handle them here.
            _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
        }
    }

    fn cast_from_float<F>(
        &self,
        f: F,
        dest_ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
    {
        use rustc::ty::TyKind::*;
        match dest_ty.sty {
            // float -> uint
            Uint(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_u128(width).value;
                // This should already fit the bit width
                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
            },
            // float -> int
            Int(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_i128(width).value;
                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
            },
            // float -> f32
            Float(FloatTy::F32) =>
                Ok(Scalar::from_f32(f.convert(&mut false).value)),
            // float -> f64
            Float(FloatTy::F64) =>
                Ok(Scalar::from_f64(f.convert(&mut false).value)),
            // That's it.
            _ => bug!("invalid float to {:?} cast", dest_ty),
        }
    }

    fn cast_from_ptr(
        &self,
        ptr: Pointer<M::PointerTag>,
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        use rustc::ty::TyKind::*;

        fn int_size<'tcx>(layout: TyLayout<'tcx>) -> Option<usize> {
            match layout.ty.sty {
                Int(i) => i.bit_width(),
                Uint(i) => i.bit_width(),
                _ => bug!("Not an integer"),
            }
        }

        match dest_layout.ty.sty {
            // Casting to a reference or fn pointer is not permitted by rustc,
            // no need to support it here.
            RawPtr(_) => Ok(ptr.into()),
            Int(IntTy::Isize) | Uint(UintTy::Usize) => {
                let size = self.memory.pointer_size();

                if let Ok(bits) = self.force_bits(Scalar::Ptr(ptr), size) {
                    self.cast_from_int(bits, src_layout, dest_layout)
                } else {
                    Ok(ptr.into())
                }
            }
            Int(_) | Uint(_) => {
                let size = Size::from_bits(int_size(dest_layout).unwrap() as u64);

                if let Ok(bits) = self.force_bits(Scalar::Ptr(ptr), size) {
                    self.cast_from_int(bits, src_layout, dest_layout)
                } else {
                    err!(ReadPointerAsBytes)
                }
            },
            // Casting to any other type is not implemented
            _ => return err!(Unimplemented(format!("ptr to {:?} cast", dest_layout.ty))),
        }
    }

    fn unsize_into_ptr(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
        // The pointee types
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
    ) -> InterpResult<'tcx> {
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::Array(_, length), &ty::Slice(_)) => {
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                // u64 cast is from usize to u64, which is always good
                let val = Immediate::new_slice(
                    ptr,
                    length.unwrap_usize(self.tcx.tcx),
                    self,
                );
                self.write_immediate(val, dest)
            }
            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                let val = self.read_immediate(src)?;
                self.write_immediate(*val, dest)
            }
            (_, &ty::Dynamic(ref data, _)) => {
                // Initial cast from sized to dyn trait
                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                let val = Immediate::new_dyn_trait(ptr, vtable);
                self.write_immediate(val, dest)
            }

            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty),
        }
    }

    fn unsize_into(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        trace!("Unsizing {:?} into {:?}", src, dest);
        match (&src.layout.ty.sty, &dest.layout.ty.sty) {
            (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
            (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
            (&ty::RawPtr(TypeAndMut { ty: s, .. }),
             &ty::RawPtr(TypeAndMut { ty: d, .. })) => {
                self.unsize_into_ptr(src, dest, s, d)
            }
            (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                assert_eq!(def_a, def_b);
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout);
                    }
                    return self.unsize_into_ptr(
                        src,
                        dest,
                        src.layout.ty.boxed_ty(),
                        dest.layout.ty.boxed_ty(),
                    );
                }

                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
                for i in 0..src.layout.fields.count() {
                    let dst_field = self.place_field(dest, i as u64)?;
                    if dst_field.layout.is_zst() {
                        continue;
                    }
                    let src_field = self.operand_field(src, i as u64)?;
                    if src_field.layout.ty == dst_field.layout.ty {
                        self.copy_op(src_field, dst_field)?;
                    } else {
                        self.unsize_into(src_field, dst_field)?;
                    }
                }
                Ok(())
            }
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
                    src.layout,
                    dest.layout
                )
            }
        }
    }
}
<|endoftext|>


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

// Spans are encoded using 1-bit tag and 2 different encoding formats (one for each tag value).
// One format is used for keeping span data inline,
// another contains index into an out-of-line span interner.
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28

use {BytePos, SpanData};
use hygiene::SyntaxContext;

use rustc_data_structures::fx::FxHashMap;
use std::cell::RefCell;

/// A compressed span.
/// Contains either fields of `SpanData` inline if they are small, or index into span interner.
/// The primary goal of `Span` is to be as small as possible and fit into other structures
/// (that's why it uses `packed` as well). Decoding speed is the second priority.
/// See `SpanData` for the info on span fields in decoded representation.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(packed)]
pub struct Span(u32);

/// Dummy span, both position and length are zero, syntax context is zero as well.
/// This span is kept inline and encoded with format 0.
pub const DUMMY_SP: Span = Span(0);

impl Span {
    #[inline]
    pub fn new(lo: BytePos, hi: BytePos, ctxt: SyntaxContext) -> Self {
        encode(&match lo <= hi {
            true => SpanData { lo, hi, ctxt },
            false => SpanData { lo: hi, hi: lo, ctxt },
        })
    }

    #[inline]
    pub fn data(self) -> SpanData {
        decode(self)
    }
}

// Tags
const TAG_INLINE: u32 = 0;
const TAG_INTERNED: u32 = 1;
const TAG_MASK: u32 = 1;

// Fields indexes
const BASE_INDEX: usize = 0;
const LEN_INDEX: usize = 1;
const CTXT_INDEX: usize = 2;

// Tag = 0, inline format.
// -----------------------------------
// | base 31:8  | len 7:1  | tag 0:0 |
// -----------------------------------
const INLINE_SIZES: [u32; 3] = [24, 7, 0];
const INLINE_OFFSETS: [u32; 3] = [8, 1, 1];

// Tag = 1, interned format.
// ------------------------
// | index 31:1 | tag 0:0 |
// ------------------------
const INTERNED_INDEX_SIZE: u32 = 31;
const INTERNED_INDEX_OFFSET: u32 = 1;

#[inline]
fn encode(sd: &SpanData) -> Span {
    let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.0);

    let val = if (base >> INLINE_SIZES[BASE_INDEX]) == 0 &&
                 (len >> INLINE_SIZES[LEN_INDEX]) == 0 &&
                 (ctxt >> INLINE_SIZES[CTXT_INDEX]) == 0 {
        (base << INLINE_OFFSETS[BASE_INDEX]) | (len << INLINE_OFFSETS[LEN_INDEX]) |
        (ctxt << INLINE_OFFSETS[CTXT_INDEX]) | TAG_INLINE
    } else {
        let index = with_span_interner(|interner| interner.intern(sd));
        (index << INTERNED_INDEX_OFFSET) | TAG_INTERNED
    };
    Span(val)
}

#[inline]
fn decode(span: Span) -> SpanData {
    let val = span.0;

    // Extract a field at position `pos` having size `size`.
    let extract = |pos: u32, size: u32| {
        let mask = ((!0u32) as u64 >> (32 - size)) as u32; // Can't shift u32 by 32
        (val >> pos) & mask
    };

    let (base, len, ctxt) = if val & TAG_MASK == TAG_INLINE {(
        extract(INLINE_OFFSETS[BASE_INDEX], INLINE_SIZES[BASE_INDEX]),
        extract(INLINE_OFFSETS[LEN_INDEX], INLINE_SIZES[LEN_INDEX]),
        extract(INLINE_OFFSETS[CTXT_INDEX], INLINE_SIZES[CTXT_INDEX]),
    )} else {
        let index = extract(INTERNED_INDEX_OFFSET, INTERNED_INDEX_SIZE);
        return with_span_interner(|interner| *interner.get(index));
    };
    SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext(ctxt) }
}

#[derive(Default)]
struct SpanInterner {
    spans: FxHashMap<SpanData, u32>,
    span_data: Vec<SpanData>,
}

impl SpanInterner {
    fn intern(&mut self, span_data: &SpanData) -> u32 {
        if let Some(index) = self.spans.get(span_data) {
            return *index;
        }

        let index = self.spans.len() as u32;
        self.span_data.push(*span_data);
        self.spans.insert(*span_data, index);
        index
    }

    #[inline]
    fn get(&self, index: u32) -> &SpanData {
        &self.span_data[index as usize]
    }
}

// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
#[inline]
fn with_span_interner<T, F: FnOnce(&mut SpanInterner) -> T>(f: F) -> T {
    thread_local!(static INTERNER: RefCell<SpanInterner> = {
        RefCell::new(SpanInterner::default())
    });
    INTERNER.with(|interner| f(&mut *interner.borrow_mut()))
}
<commit_msg>Auto merge of #45758 - nzig:explain-span-ctxt, r=petrochenkov<commit_after>// Copyright 2017 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.

// Spans are encoded using 1-bit tag and 2 different encoding formats (one for each tag value).
// One format is used for keeping span data inline,
// another contains index into an out-of-line span interner.
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28

use {BytePos, SpanData};
use hygiene::SyntaxContext;

use rustc_data_structures::fx::FxHashMap;
use std::cell::RefCell;

/// A compressed span.
/// Contains either fields of `SpanData` inline if they are small, or index into span interner.
/// The primary goal of `Span` is to be as small as possible and fit into other structures
/// (that's why it uses `packed` as well). Decoding speed is the second priority.
/// See `SpanData` for the info on span fields in decoded representation.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(packed)]
pub struct Span(u32);

/// Dummy span, both position and length are zero, syntax context is zero as well.
/// This span is kept inline and encoded with format 0.
pub const DUMMY_SP: Span = Span(0);

impl Span {
    #[inline]
    pub fn new(lo: BytePos, hi: BytePos, ctxt: SyntaxContext) -> Self {
        encode(&match lo <= hi {
            true => SpanData { lo, hi, ctxt },
            false => SpanData { lo: hi, hi: lo, ctxt },
        })
    }

    #[inline]
    pub fn data(self) -> SpanData {
        decode(self)
    }
}

// Tags
const TAG_INLINE: u32 = 0;
const TAG_INTERNED: u32 = 1;
const TAG_MASK: u32 = 1;

// Fields indexes
const BASE_INDEX: usize = 0;
const LEN_INDEX: usize = 1;
const CTXT_INDEX: usize = 2;

// Tag = 0, inline format.
// -------------------------------------------------------------
// | base 31:8  | len 7:1  | ctxt (currently 0 bits) | tag 0:0 |
// -------------------------------------------------------------
// Since there are zero bits for ctxt, only SpanData with a 0 SyntaxContext
// can be inline.
const INLINE_SIZES: [u32; 3] = [24, 7, 0];
const INLINE_OFFSETS: [u32; 3] = [8, 1, 1];

// Tag = 1, interned format.
// ------------------------
// | index 31:1 | tag 0:0 |
// ------------------------
const INTERNED_INDEX_SIZE: u32 = 31;
const INTERNED_INDEX_OFFSET: u32 = 1;

#[inline]
fn encode(sd: &SpanData) -> Span {
    let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.0);

    let val = if (base >> INLINE_SIZES[BASE_INDEX]) == 0 &&
                 (len >> INLINE_SIZES[LEN_INDEX]) == 0 &&
                 (ctxt >> INLINE_SIZES[CTXT_INDEX]) == 0 {
        (base << INLINE_OFFSETS[BASE_INDEX]) | (len << INLINE_OFFSETS[LEN_INDEX]) |
        (ctxt << INLINE_OFFSETS[CTXT_INDEX]) | TAG_INLINE
    } else {
        let index = with_span_interner(|interner| interner.intern(sd));
        (index << INTERNED_INDEX_OFFSET) | TAG_INTERNED
    };
    Span(val)
}

#[inline]
fn decode(span: Span) -> SpanData {
    let val = span.0;

    // Extract a field at position `pos` having size `size`.
    let extract = |pos: u32, size: u32| {
        let mask = ((!0u32) as u64 >> (32 - size)) as u32; // Can't shift u32 by 32
        (val >> pos) & mask
    };

    let (base, len, ctxt) = if val & TAG_MASK == TAG_INLINE {(
        extract(INLINE_OFFSETS[BASE_INDEX], INLINE_SIZES[BASE_INDEX]),
        extract(INLINE_OFFSETS[LEN_INDEX], INLINE_SIZES[LEN_INDEX]),
        extract(INLINE_OFFSETS[CTXT_INDEX], INLINE_SIZES[CTXT_INDEX]),
    )} else {
        let index = extract(INTERNED_INDEX_OFFSET, INTERNED_INDEX_SIZE);
        return with_span_interner(|interner| *interner.get(index));
    };
    SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext(ctxt) }
}

#[derive(Default)]
struct SpanInterner {
    spans: FxHashMap<SpanData, u32>,
    span_data: Vec<SpanData>,
}

impl SpanInterner {
    fn intern(&mut self, span_data: &SpanData) -> u32 {
        if let Some(index) = self.spans.get(span_data) {
            return *index;
        }

        let index = self.spans.len() as u32;
        self.span_data.push(*span_data);
        self.spans.insert(*span_data, index);
        index
    }

    #[inline]
    fn get(&self, index: u32) -> &SpanData {
        &self.span_data[index as usize]
    }
}

// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
#[inline]
fn with_span_interner<T, F: FnOnce(&mut SpanInterner) -> T>(f: F) -> T {
    thread_local!(static INTERNER: RefCell<SpanInterner> = {
        RefCell::new(SpanInterner::default())
    });
    INTERNER.with(|interner| f(&mut *interner.borrow_mut()))
}
<|endoftext|>


<commit_before>mod batch;

pub use self::batch::BatchItem;

use self::batch::generate_batch_payload;
use std::io::Read;
use mime;
use mime::Mime;
use azure::core;
use azure::core::errors::{self, AzureError, check_status_extract_body,
                          check_status_extract_headers_and_body, extract_status_and_body,
                          UnexpectedHTTPResult};
use azure::storage::client::Client;
use azure::storage::rest_client::ServiceType;
use hyper::Method;
use hyper::client::FutureResponse;
use hyper::header::{Accept, ContentType, Headers, IfMatch, qitem};
use hyper::StatusCode;
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json;

use futures::future::*;

const TABLE_TABLES: &'static str = "TABLES";

pub struct TableService {
    client: Client,
}

impl TableService {
    pub fn new(client: Client) -> Self {
        TableService { client: client }
    }

    //pub fn list_tables(&self) -> Result<Vec<String>, AzureError> {
    //    Ok(
    //        self.query_entities(TABLE_TABLES, None)?
    //            .into_iter()
    //            .map(|x: TableEntity| x.TableName)
    //            .collect(),
    //    )
    //}

    // Create table if not exists.
    pub fn create_table<T: Into<String>>(
        &self,
        table_name: T,
    ) -> impl Future<Item = (), Error = AzureError> {
        let body = &serde_json::to_string(&TableEntity { TableName: table_name.into() }).unwrap();
        debug!("body == {}", body);
        let req = self.request_with_default_header(TABLE_TABLES, Method::Post, Some(body));

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Created)
                .and_then(move |_| ok(()))
        })
    }

    pub fn get_entity<T: DeserializeOwned>(
        &self,
        table_name: &str,
        partition_key: &str,
        row_key: &str,
    ) -> impl Future<Item = Option<T>, Error = AzureError> {
        let path = &entity_path(table_name, partition_key, row_key);
        let req = self.request_with_default_header(path, Method::Get, None);
        done(req).from_err().and_then(move |future_response| {
            extract_status_and_body(future_response).and_then(
                move |(status, body)| if status == StatusCode::NotFound {
                    ok(None)
                } else if status != StatusCode::Ok {
                    err(AzureError::UnexpectedHTTPResult(
                        UnexpectedHTTPResult::new(StatusCode::Ok, status, &body),
                    ))
                } else {
                    match serde_json::from_str(&body) {
                        Ok(item) => ok(Some(item)),
                        Err(error) => err(error.into()),
                    }
                },
            )
        })
    }

    pub fn query_entities<T: DeserializeOwned>(
        &self,
        table_name: &str,
        query: Option<&str>,
    ) -> impl Future<Item = Vec<T>, Error = AzureError> {
        let mut path = table_name.to_owned();
        if let Some(clause) = query {
            path.push_str("?");
            path.push_str(clause);
        }

        let req = self.request_with_default_header(path.as_str(), Method::Get, None);

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Ok).and_then(move |body| {
                done(serde_json::from_str::<EntityCollection<T>>(&body))
                    .from_err()
                    .and_then(|ec| ok(ec.value))
            })
        })
    }

    //pub fn insert_entity<T: Serialize>(
    //    &self,
    //    table_name: &str,
    //    entity: &T,
    //) -> Result<(), AzureError> {
    //    let body = &serde_json::to_string(entity).unwrap();
    //    let mut resp = try!(self.request_with_default_header(
    //        table_name,
    //        Method::Post,
    //        Some(body)
    //    ));
    //    try!(errors::check_status(&mut resp, StatusCode::Created));
    //    Ok(())
    //}

    //pub fn update_entity<T: Serialize>(
    //    &self,
    //    table_name: &str,
    //    partition_key: &str,
    //    row_key: &str,
    //    entity: &T,
    //) -> Result<(), AzureError> {
    //    let body = &serde_json::to_string(entity).unwrap();
    //    let path = &entity_path(table_name, partition_key, row_key);
    //    let mut resp = try!(self.request_with_default_header(
    //        path,
    //        Method::Put,
    //        Some(body)
    //    ));
    //    try!(errors::check_status(&mut resp, StatusCode::NoContent));
    //    Ok(())
    //}

    //pub fn delete_entity(
    //    &self,
    //    table_name: &str,
    //    partition_key: &str,
    //    row_key: &str,
    //) -> Result<(), AzureError> {
    //    let path = &entity_path(table_name, partition_key, row_key);
    //    let mut headers = Headers::new();
    //    headers.set(Accept(vec![qitem(get_json_mime_nometadata())]));
    //    headers.set(IfMatch::Any);

    //    let mut resp = try!(self.request(path, Method::Delete, None, headers));
    //    try!(errors::check_status(&mut resp, StatusCode::NoContent));
    //    Ok(())
    //}

    //pub fn batch<T: Serialize>(
    //    &self,
    //    table_name: &str,
    //    partition_key: &str,
    //    batch_items: &[BatchItem<T>],
    //) -> Result<(), AzureError> {
    //    let payload = &generate_batch_payload(
    //        self.client.get_uri_prefix(ServiceType::Table).as_str(),
    //        table_name,
    //        partition_key,
    //        batch_items,
    //    );
    //    let mut headers = Headers::new();
    //    headers.set(ContentType(get_batch_mime()));
    //    let mut response = try!(self.request("$batch", Method::Post, Some(payload), headers));
    //    try!(errors::check_status(&mut response, StatusCode::Accepted));
    //    // TODO deal with body response, handle batch failure.
    //    // let ref body = try!(get_response_body(&mut response));
    //    // info!("{}", body);
    //    Ok(())
    //}

    fn request_with_default_header(
        &self,
        segment: &str,
        method: Method,
        request_str: Option<&str>,
    ) -> Result<FutureResponse, AzureError> {
        let mut headers = Headers::new();
        self.request(segment, method, request_str, |ref mut headers| {
            headers.set(Accept(vec![qitem(get_json_mime_nometadata())]));
            if request_str.is_some() {
                headers.set(ContentType(get_default_json_mime()));
            }
        })
    }

    fn request<F>(
        &self,
        segment: &str,
        method: Method,
        request_str: Option<&str>,
        headers_func: F,
    ) -> Result<FutureResponse, AzureError>
    where
        F: FnOnce(&mut Headers),
    {
        trace!("{:?} {}", method, segment);
        if let Some(body) = request_str {
            trace!("Request: {}", body);
        }

        let request_vec: Option<&[u8]> = match request_str {
            Some(s) => Some(s.as_bytes()),
            None => None,
        };

        self.client
            .perform_table_request(segment, method, headers_func, request_vec)
    }
}

#[allow(non_snake_case)]
#[derive(Serialize, Deserialize)]
struct TableEntity {
    TableName: String,
}

#[derive(Deserialize)]
struct EntityCollection<T> {
    value: Vec<T>,
}

//fn get_response_body(resp: &mut Response) -> Result<String, AzureError> {
//    let mut body = String::new();
//    try!(resp.read_to_string(&mut body));
//    trace!("Response Body:{}", body);
//    Ok(body)
//}

#[inline]
fn entity_path(table_name: &str, partition_key: &str, row_key: &str) -> String {
    table_name.to_owned() + "(PartitionKey='" + partition_key + "',RowKey='" + row_key + "')"
}

#[inline]
pub fn get_default_json_mime() -> Mime {
    "application/json; charset=utf-8".parse().unwrap()
}

#[inline]
pub fn get_json_mime_nometadata() -> Mime {
    "application/json; odata=nometadata".parse().unwrap()
}

#[inline]
pub fn get_batch_mime() -> Mime {
    "multipart/mixed; boundary=batch_a1e9d677-b28b-435e-a89e-87e6a768a431"
        .parse()
        .unwrap()
}
<commit_msg>insert and update entity<commit_after>mod batch;

pub use self::batch::BatchItem;

use self::batch::generate_batch_payload;
use std::io::Read;
use mime;
use mime::Mime;
use azure::core;
use azure::core::errors::{self, AzureError, check_status_extract_body,
                          check_status_extract_headers_and_body, extract_status_and_body,
                          UnexpectedHTTPResult};
use azure::storage::client::Client;
use azure::storage::rest_client::ServiceType;
use hyper::Method;
use hyper::client::FutureResponse;
use hyper::header::{Accept, ContentType, Headers, IfMatch, qitem};
use hyper::StatusCode;
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json;

use futures::future::*;

const TABLE_TABLES: &'static str = "TABLES";

pub struct TableService {
    client: Client,
}

impl TableService {
    pub fn new(client: Client) -> Self {
        TableService { client: client }
    }

    pub fn list_tables(&self) -> impl Future<Item = Vec<String>, Error = AzureError> {
        self.query_entities(TABLE_TABLES, None).and_then(
            |entities| {
                let e: Vec<String> = entities
                    .into_iter()
                    .map(|x: TableEntity| x.TableName)
                    .collect();
                ok(e)
            },
        )
    }

    // Create table if not exists.
    pub fn create_table<T: Into<String>>(
        &self,
        table_name: T,
    ) -> impl Future<Item = (), Error = AzureError> {
        let body = &serde_json::to_string(&TableEntity { TableName: table_name.into() }).unwrap();
        debug!("body == {}", body);
        let req = self.request_with_default_header(TABLE_TABLES, Method::Post, Some(body));

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Created)
                .and_then(move |_| ok(()))
        })
    }

    pub fn get_entity<T: DeserializeOwned>(
        &self,
        table_name: &str,
        partition_key: &str,
        row_key: &str,
    ) -> impl Future<Item = Option<T>, Error = AzureError> {
        let path = &entity_path(table_name, partition_key, row_key);
        let req = self.request_with_default_header(path, Method::Get, None);
        done(req).from_err().and_then(move |future_response| {
            extract_status_and_body(future_response).and_then(
                move |(status, body)| if status == StatusCode::NotFound {
                    ok(None)
                } else if status != StatusCode::Ok {
                    err(AzureError::UnexpectedHTTPResult(
                        UnexpectedHTTPResult::new(StatusCode::Ok, status, &body),
                    ))
                } else {
                    match serde_json::from_str(&body) {
                        Ok(item) => ok(Some(item)),
                        Err(error) => err(error.into()),
                    }
                },
            )
        })
    }

    pub fn query_entities<T: DeserializeOwned>(
        &self,
        table_name: &str,
        query: Option<&str>,
    ) -> impl Future<Item = Vec<T>, Error = AzureError> {
        let mut path = table_name.to_owned();
        if let Some(clause) = query {
            path.push_str("?");
            path.push_str(clause);
        }

        let req = self.request_with_default_header(path.as_str(), Method::Get, None);

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Ok).and_then(move |body| {
                done(serde_json::from_str::<EntityCollection<T>>(&body))
                    .from_err()
                    .and_then(|ec| ok(ec.value))
            })
        })
    }

    fn _prepare_insert_entity<T>(
        &self,
        table_name: &str,
        entity: &T,
    ) -> Result<FutureResponse, AzureError>
    where
        T: Serialize,
    {
        let obj_ser = serde_json::to_string(entity)?;
        self.request_with_default_header(table_name, Method::Post, Some(&obj_ser))
    }

    pub fn insert_entity<T: Serialize>(
        &self,
        table_name: &str,
        entity: &T,
    ) -> impl Future<Item = (), Error = AzureError> {
        let req = self._prepare_insert_entity(table_name, entity);

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Created)
                .and_then(move |_| ok(()))
        })
    }

    fn _prepare_update_entity<T>(
        &self,
        table_name: &str,
        partition_key: &str,
        row_key: &str,
        entity: &T,
    ) -> Result<FutureResponse, AzureError>
    where
        T: Serialize,
    {
        let body = &serde_json::to_string(entity)?;
        let path = &entity_path(table_name, partition_key, row_key);
        self.request_with_default_header(path, Method::Put, Some(body))
    }

    pub fn update_entity<T: Serialize>(
        &self,
        table_name: &str,
        partition_key: &str,
        row_key: &str,
        entity: &T,
    ) -> impl Future<Item = (), Error = AzureError> {
        let req = _prepare_update_entity(table_name, partition_key, row_key, entity);
        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::NoContent)
                .and_then(move |_| ok(()))
        })
    }

    //pub fn delete_entity(
    //    &self,
    //    table_name: &str,
    //    partition_key: &str,
    //    row_key: &str,
    //) -> Result<(), AzureError> {
    //    let path = &entity_path(table_name, partition_key, row_key);
    //    let mut headers = Headers::new();
    //    headers.set(Accept(vec![qitem(get_json_mime_nometadata())]));
    //    headers.set(IfMatch::Any);

    //    let mut resp = try!(self.request(path, Method::Delete, None, headers));
    //    try!(errors::check_status(&mut resp, StatusCode::NoContent));
    //    Ok(())
    //}

    //pub fn batch<T: Serialize>(
    //    &self,
    //    table_name: &str,
    //    partition_key: &str,
    //    batch_items: &[BatchItem<T>],
    //) -> Result<(), AzureError> {
    //    let payload = &generate_batch_payload(
    //        self.client.get_uri_prefix(ServiceType::Table).as_str(),
    //        table_name,
    //        partition_key,
    //        batch_items,
    //    );
    //    let mut headers = Headers::new();
    //    headers.set(ContentType(get_batch_mime()));
    //    let mut response = try!(self.request("$batch", Method::Post, Some(payload), headers));
    //    try!(errors::check_status(&mut response, StatusCode::Accepted));
    //    // TODO deal with body response, handle batch failure.
    //    // let ref body = try!(get_response_body(&mut response));
    //    // info!("{}", body);
    //    Ok(())
    //}

    fn request_with_default_header(
        &self,
        segment: &str,
        method: Method,
        request_str: Option<&str>,
    ) -> Result<FutureResponse, AzureError> {
        let mut headers = Headers::new();
        self.request(segment, method, request_str, |ref mut headers| {
            headers.set(Accept(vec![qitem(get_json_mime_nometadata())]));
            if request_str.is_some() {
                headers.set(ContentType(get_default_json_mime()));
            }
        })
    }

    fn request<F>(
        &self,
        segment: &str,
        method: Method,
        request_str: Option<&str>,
        headers_func: F,
    ) -> Result<FutureResponse, AzureError>
    where
        F: FnOnce(&mut Headers),
    {
        trace!("{:?} {}", method, segment);
        if let Some(body) = request_str {
            trace!("Request: {}", body);
        }

        let request_vec: Option<&[u8]> = match request_str {
            Some(s) => Some(s.as_bytes()),
            None => None,
        };

        self.client
            .perform_table_request(segment, method, headers_func, request_vec)
    }
}

#[allow(non_snake_case)]
#[derive(Serialize, Deserialize)]
struct TableEntity {
    TableName: String,
}

#[derive(Deserialize)]
struct EntityCollection<T> {
    value: Vec<T>,
}

//fn get_response_body(resp: &mut Response) -> Result<String, AzureError> {
//    let mut body = String::new();
//    try!(resp.read_to_string(&mut body));
//    trace!("Response Body:{}", body);
//    Ok(body)
//}

#[inline]
fn entity_path(table_name: &str, partition_key: &str, row_key: &str) -> String {
    table_name.to_owned() + "(PartitionKey='" + partition_key + "',RowKey='" + row_key + "')"
}

#[inline]
pub fn get_default_json_mime() -> Mime {
    "application/json; charset=utf-8".parse().unwrap()
}

#[inline]
pub fn get_json_mime_nometadata() -> Mime {
    "application/json; odata=nometadata".parse().unwrap()
}

#[inline]
pub fn get_batch_mime() -> Mime {
    "multipart/mixed; boundary=batch_a1e9d677-b28b-435e-a89e-87e6a768a431"
        .parse()
        .unwrap()
}
<|endoftext|>


<commit_before>use std::fs;
use std::path::{ Path, PathBuf };

use find_package;

fn uninstall(name: &str, path: &Path) -> Result<bool, String> {
    let package = find_package::select_package(name, path);
    let mut installation_path = PathBuf::new();

    installation_path.push(path);
    installation_path.push(format!("install/{}", package.name));

    if installation_path.exists() {
        fs::remove_dir_all(&path)?;
        return Ok(true)
    } else {
        return Ok(false)
    }
}<commit_msg>Full uninstallation functionality<commit_after>use std::fs;
use std::path::{ Path, PathBuf };

use find_package;

fn uninstall(name: &str, path: &Path) -> Result<bool, String> {
    let package = find_package::select_package(name, path);

    let mut installation_path = PathBuf::new();
            installation_path.push(path);
            installation_path.push(format!("install/{}", package.name));

    if installation_path.exists() {
        fs::remove_dir_all(&path)?;
        return Ok(true)
    } else {
        return Ok(false)
    }
}

fn full_uninstall(name: &str, path: &Path) -> Result<bool, String> {
    uninstall(name, path)?;

    let mut download_path = PathBuf::new();
            download_path.push(path);
            download_path.push(format!("download/{}", package.name));
    fs::remove_file(tar_path)?;

    let mut tar_path = PathBuf::new();
            tar_path.push(path);
            tar_path.push(format!("download/{}.tar", package.name));
    fs::remove_file(tar_path)?;

    return Ok(true)
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::collections::HashSet;

#[derive(Serialize, Clone)]
pub enum ExtRange {
#[serde(rename = "gene")]
    Gene(GeneShort),
#[serde(rename = "term")]
    Term(TermShort),
#[serde(rename = "misc")]
    Misc(String),
}

#[derive(Serialize, Clone)]
pub struct ExtPart {
    pub rel_type_name: String,
    pub ext_range: ExtRange,
}

#[derive(Serialize, Clone)]
pub struct GeneShort {
    pub uniquename: GeneUniquename,
    pub name: Option<GeneName>,
    pub product: Option<GeneProduct>,
    pub synonyms: Vec<SynonymDetails>,
}

pub struct TermIdPair {
    pub firstid: TermId,
    pub secondid: TermId,
}

impl TermIdPair {
    pub fn new(firstid: &TermId, secondid: &TermId) -> TermIdPair {
        TermIdPair {
            firstid: firstid.clone(),
            secondid: secondid.clone(),
        }
    }
}

impl PartialEq for TermIdPair {
    fn eq(&self, other: &TermIdPair) -> bool {
        self.firstid == other.firstid &&
            self.secondid == other.secondid
    }
}
impl Eq for TermIdPair { }
impl Hash for TermIdPair {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.firstid.hash(state);
        self.secondid.hash(state);
    }
}

impl PartialEq for GeneShort {
    fn eq(&self, other: &GeneShort) -> bool {
        self.uniquename == other.uniquename
    }
}
impl Eq for GeneShort { }
impl Ord for GeneShort {
    fn cmp(&self, other: &GeneShort) -> Ordering {
        if self.name.is_some() {
            if other.name.is_some() {
                self.name.cmp(&other.name)
            } else { Ordering::Less }
        } else {
            if other.name.is_some() {
                Ordering::Greater
            } else { self.uniquename.cmp(&other.uniquename) }
        }
    }
}
impl PartialOrd for GeneShort {
    fn partial_cmp(&self, other: &GeneShort) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Hash for GeneShort {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.uniquename.hash(state);
    }
}

#[derive(Serialize, Clone)]
pub struct TranscriptShort {
    pub uniquename: TranscriptUniquename,
    //                pub exons: Vec<ExonShort>,
    //                pub utrs: Vec<UTRShort>,
}

#[derive(Serialize, Clone)]
pub struct TermShort {
    pub name: TermName,
    pub cv_name: String,
    pub termid: TermId,
    pub is_obsolete: bool,
    pub gene_count: Option<usize>,
}

#[derive(Serialize, Clone)]
pub struct ReferenceShort {
    pub uniquename: String,
    pub title: Option<String>,
    pub citation: Option<String>,
    pub authors_abbrev: Option<String>,
    pub publication_year: Option<String>,
}

#[derive(Serialize, Clone)]
pub struct ReferenceDetails {
    pub uniquename: String,
    pub title: Option<String>,
    pub citation: Option<String>,
    pub authors: Option<String>,
    pub authors_abbrev: Option<String>,
    pub pubmed_publication_date: Option<String>,
    pub publication_year: Option<String>,
    pub annotations: OntAnnotationMap,
    pub interaction_annotations: TypeInteractionAnnotationMap,
    pub ortholog_annotations: Vec<OrthologAnnotation>,
    pub paralog_annotations: Vec<ParalogAnnotation>,
}

#[derive(Serialize, Clone)]
pub struct OntAnnotation {
    pub id: i32,
    pub term: Option<TermShort>,
    pub gene: Option<GeneShort>,
    pub reference: Option<ReferenceShort>,
    pub evidence: Option<Evidence>,
    pub extension: Vec<ExtPart>,
    pub with: Option<With>,
    pub residue: Option<Residue>,
    pub qualifiers: Vec<Qualifier>,
    pub gene_ex_props: Option<GeneExProps>,
    // only for genotype/phenotype annotation:
    pub genotype: Option<GenotypeShort>,
    pub conditions: Vec<TermShort>,
    pub is_not: bool,
}

#[derive(Serialize, Clone)]
pub struct SynonymDetails {
    pub name: String,
    pub synonym_type: String
}

#[derive(Serialize, Clone)]
pub enum Strand {
    #[serde(rename="forward")]
    Forward = 1,
    #[serde(rename="reverse")]
    Reverse = -1,
}

#[derive(Serialize, Clone)]
pub struct ChromosomeLocation {
    pub chromosome_name: String,
    pub start_pos: u32,
    pub end_pos: u32,
    pub strand: Strand,
}

#[derive(Serialize, Clone)]
pub struct OrganismShort {
    pub genus: String,
    pub species: String,
}

#[derive(Serialize, Clone)]
pub struct GeneDetails {
    pub uniquename: GeneUniquename,
    pub name: Option<String>,
    pub organism: OrganismShort,
    pub product: Option<String>,
    pub synonyms: Vec<SynonymDetails>,
    pub feature_type: String,
    pub characterisation_status: Option<String>,
    pub location: Option<ChromosomeLocation>,
    pub cds_location: Option<ChromosomeLocation>,
    pub transcripts: Vec<TranscriptShort>,
    pub annotations: OntAnnotationMap,
    pub interaction_annotations: TypeInteractionAnnotationMap,
    pub ortholog_annotations: Vec<OrthologAnnotation>,
    pub paralog_annotations: Vec<ParalogAnnotation>,
}

#[derive(Serialize, Clone)]
pub struct TranscriptDetails {
    pub uniquename: TranscriptUniquename,
    pub name: Option<String>,
//    pub annotations: TypeFeatureAnnotationMap,
}

#[derive(Serialize, Clone)]
pub struct GenotypeShort {
    pub uniquename: GenotypeUniquename,
    pub name: Option<String>,
    pub background: Option<String>,
    pub expressed_alleles: Vec<ExpressedAllele>,
//    pub annotations: TypeFeatureAnnotationMap,
}

#[derive(Serialize, Clone)]
pub struct ExpressedAllele {
    pub expression: Option<String>,
    pub allele: AlleleShort,
}

#[derive(Serialize, Clone)]
pub struct AlleleShort {
    pub uniquename: String,
    pub name: Option<String>,
    pub allele_type: String,
    pub description: Option<String>,
    pub gene: GeneShort,
}

pub type RelName = String;

#[derive(Serialize, Clone)]
pub struct GeneExProps {
    #[serde(skip_serializing_if="Option::is_none")]
    pub copies_per_cell: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub avg_copies_per_cell: Option<String>,
}

pub type OntName = String;
pub type OntAnnotationMap = HashMap<OntName, Vec<Rc<OntAnnotation>>>;

#[derive(Serialize, Clone)]
pub struct RelOntAnnotation {
    pub rel_names: HashSet<RelName>,
    pub annotation: Rc<OntAnnotation>,
}

#[derive(Serialize, Clone)]
pub struct TermDetails {
    pub name: TermName,
    pub cv_name: CvName,
    pub termid: TermId,
    pub definition: Option<TermDef>,
    pub is_obsolete: bool,
    pub genes: Vec<GeneShort>,
    pub annotations: Vec<RelOntAnnotation>,
}

#[derive(Serialize, Clone)]
pub struct InteractionAnnotation {
    pub gene: GeneShort,
    pub interactor: GeneShort,
    pub evidence: Option<Evidence>,
    pub reference: Option<ReferenceShort>,
}

#[derive(Serialize, Clone)]
pub struct OrthologAnnotation {
    pub gene: GeneShort,
    pub ortholog_organism: OrganismShort,
    pub ortholog: GeneShort,
    pub evidence: Option<Evidence>,
    pub reference: Option<ReferenceShort>,
}

#[derive(Serialize, Clone)]
pub struct ParalogAnnotation {
    pub gene: GeneShort,
    pub paralog: GeneShort,
    pub evidence: Option<Evidence>,
    pub reference: Option<ReferenceShort>,
}

#[derive(Serialize, Clone)]
pub struct Metadata {
    pub db_creation_datetime: String,
    pub export_prog_name: String,
    pub export_prog_version: String,
    pub gene_count: usize,
    pub term_count: usize,
}

#[derive(Serialize, Clone)]
pub struct WebData {
    pub genes: IdGeneMap,
    pub gene_summaries: IdGeneShortMap,
    pub terms: IdTermDetailsMap,
    pub used_terms: IdTermDetailsMap,
    pub metadata: Metadata,
    pub references: IdReferenceMap,
}
<commit_msg>Don't write nulls to JSON<commit_after>use std::rc::Rc;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::collections::HashSet;

#[derive(Serialize, Clone)]
pub enum ExtRange {
#[serde(rename = "gene")]
    Gene(GeneShort),
#[serde(rename = "term")]
    Term(TermShort),
#[serde(rename = "misc")]
    Misc(String),
}

#[derive(Serialize, Clone)]
pub struct ExtPart {
    pub rel_type_name: String,
    pub ext_range: ExtRange,
}

#[derive(Serialize, Clone)]
pub struct GeneShort {
    pub uniquename: GeneUniquename,
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<GeneName>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub product: Option<GeneProduct>,
    pub synonyms: Vec<SynonymDetails>,
}

pub struct TermIdPair {
    pub firstid: TermId,
    pub secondid: TermId,
}

impl TermIdPair {
    pub fn new(firstid: &TermId, secondid: &TermId) -> TermIdPair {
        TermIdPair {
            firstid: firstid.clone(),
            secondid: secondid.clone(),
        }
    }
}

impl PartialEq for TermIdPair {
    fn eq(&self, other: &TermIdPair) -> bool {
        self.firstid == other.firstid &&
            self.secondid == other.secondid
    }
}
impl Eq for TermIdPair { }
impl Hash for TermIdPair {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.firstid.hash(state);
        self.secondid.hash(state);
    }
}

impl PartialEq for GeneShort {
    fn eq(&self, other: &GeneShort) -> bool {
        self.uniquename == other.uniquename
    }
}
impl Eq for GeneShort { }
impl Ord for GeneShort {
    fn cmp(&self, other: &GeneShort) -> Ordering {
        if self.name.is_some() {
            if other.name.is_some() {
                self.name.cmp(&other.name)
            } else { Ordering::Less }
        } else {
            if other.name.is_some() {
                Ordering::Greater
            } else { self.uniquename.cmp(&other.uniquename) }
        }
    }
}
impl PartialOrd for GeneShort {
    fn partial_cmp(&self, other: &GeneShort) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Hash for GeneShort {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.uniquename.hash(state);
    }
}

#[derive(Serialize, Clone)]
pub struct TranscriptShort {
    pub uniquename: TranscriptUniquename,
    //                pub exons: Vec<ExonShort>,
    //                pub utrs: Vec<UTRShort>,
}

#[derive(Serialize, Clone)]
pub struct TermShort {
    pub name: TermName,
    pub cv_name: String,
    pub termid: TermId,
    pub is_obsolete: bool,
    #[serde(skip_serializing_if="Option::is_none")]
    pub gene_count: Option<usize>,
}

#[derive(Serialize, Clone)]
pub struct ReferenceShort {
    pub uniquename: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub title: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub citation: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub authors_abbrev: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub publication_year: Option<String>,
}

#[derive(Serialize, Clone)]
pub struct ReferenceDetails {
    pub uniquename: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub title: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub citation: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub authors: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub authors_abbrev: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub pubmed_publication_date: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub publication_year: Option<String>,
    pub annotations: OntAnnotationMap,
    pub interaction_annotations: TypeInteractionAnnotationMap,
    pub ortholog_annotations: Vec<OrthologAnnotation>,
    pub paralog_annotations: Vec<ParalogAnnotation>,
}

#[derive(Serialize, Clone)]
pub struct OntAnnotation {
    pub id: i32,
    #[serde(skip_serializing_if="Option::is_none")]
    pub term: Option<TermShort>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub gene: Option<GeneShort>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub reference: Option<ReferenceShort>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub evidence: Option<Evidence>,
    pub extension: Vec<ExtPart>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub with: Option<With>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub residue: Option<Residue>,
    pub qualifiers: Vec<Qualifier>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub gene_ex_props: Option<GeneExProps>,
    // only for genotype/phenotype annotation:
    #[serde(skip_serializing_if="Option::is_none")]
    pub genotype: Option<GenotypeShort>,
    pub conditions: Vec<TermShort>,
    pub is_not: bool,
}

#[derive(Serialize, Clone)]
pub struct SynonymDetails {
    pub name: String,
    pub synonym_type: String
}

#[derive(Serialize, Clone)]
pub enum Strand {
    #[serde(rename="forward")]
    Forward = 1,
    #[serde(rename="reverse")]
    Reverse = -1,
}

#[derive(Serialize, Clone)]
pub struct ChromosomeLocation {
    pub chromosome_name: String,
    pub start_pos: u32,
    pub end_pos: u32,
    pub strand: Strand,
}

#[derive(Serialize, Clone)]
pub struct OrganismShort {
    pub genus: String,
    pub species: String,
}

#[derive(Serialize, Clone)]
pub struct GeneDetails {
    pub uniquename: GeneUniquename,
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<String>,
    pub organism: OrganismShort,
    #[serde(skip_serializing_if="Option::is_none")]
    pub product: Option<String>,
    pub synonyms: Vec<SynonymDetails>,
    pub feature_type: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub characterisation_status: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub location: Option<ChromosomeLocation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub cds_location: Option<ChromosomeLocation>,
    pub transcripts: Vec<TranscriptShort>,
    pub annotations: OntAnnotationMap,
    pub interaction_annotations: TypeInteractionAnnotationMap,
    pub ortholog_annotations: Vec<OrthologAnnotation>,
    pub paralog_annotations: Vec<ParalogAnnotation>,
}

#[derive(Serialize, Clone)]
pub struct TranscriptDetails {
    pub uniquename: TranscriptUniquename,
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<String>,
//    pub annotations: TypeFeatureAnnotationMap,
}

#[derive(Serialize, Clone)]
pub struct GenotypeShort {
    pub uniquename: GenotypeUniquename,
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub background: Option<String>,
    pub expressed_alleles: Vec<ExpressedAllele>,
//    pub annotations: TypeFeatureAnnotationMap,
}

#[derive(Serialize, Clone)]
pub struct ExpressedAllele {
    #[serde(skip_serializing_if="Option::is_none")]
    pub expression: Option<String>,
    pub allele: AlleleShort,
}

#[derive(Serialize, Clone)]
pub struct AlleleShort {
    pub uniquename: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<String>,
    pub allele_type: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    pub gene: GeneShort,
}

pub type RelName = String;

#[derive(Serialize, Clone)]
pub struct GeneExProps {
    #[serde(skip_serializing_if="Option::is_none")]
    pub copies_per_cell: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub avg_copies_per_cell: Option<String>,
}

pub type OntName = String;
pub type OntAnnotationMap = HashMap<OntName, Vec<Rc<OntAnnotation>>>;

#[derive(Serialize, Clone)]
pub struct RelOntAnnotation {
    pub rel_names: HashSet<RelName>,
    pub annotation: Rc<OntAnnotation>,
}

#[derive(Serialize, Clone)]
pub struct TermDetails {
    pub name: TermName,
    pub cv_name: CvName,
    pub termid: TermId,
    #[serde(skip_serializing_if="Option::is_none")]
    pub definition: Option<TermDef>,
    pub is_obsolete: bool,
    pub genes: Vec<GeneShort>,
    pub annotations: Vec<RelOntAnnotation>,
}

#[derive(Serialize, Clone)]
pub struct InteractionAnnotation {
    pub gene: GeneShort,
    pub interactor: GeneShort,
    #[serde(skip_serializing_if="Option::is_none")]
    pub evidence: Option<Evidence>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub reference: Option<ReferenceShort>,
}

#[derive(Serialize, Clone)]
pub struct OrthologAnnotation {
    pub gene: GeneShort,
    pub ortholog_organism: OrganismShort,
    pub ortholog: GeneShort,
    #[serde(skip_serializing_if="Option::is_none")]
    pub evidence: Option<Evidence>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub reference: Option<ReferenceShort>,
}

#[derive(Serialize, Clone)]
pub struct ParalogAnnotation {
    pub gene: GeneShort,
    pub paralog: GeneShort,
    #[serde(skip_serializing_if="Option::is_none")]
    pub evidence: Option<Evidence>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub reference: Option<ReferenceShort>,
}

#[derive(Serialize, Clone)]
pub struct Metadata {
    pub db_creation_datetime: String,
    pub export_prog_name: String,
    pub export_prog_version: String,
    pub gene_count: usize,
    pub term_count: usize,
}

#[derive(Serialize, Clone)]
pub struct WebData {
    pub genes: IdGeneMap,
    pub gene_summaries: IdGeneShortMap,
    pub terms: IdTermDetailsMap,
    pub used_terms: IdTermDetailsMap,
    pub metadata: Metadata,
    pub references: IdReferenceMap,
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use raftstore::store::{PeerStorage, keys};
use raftstore::store::engine::Iterable;
use util::worker::Runnable;
use util::rocksdb;
use storage::CF_RAFT;

use rocksdb::{DB, WriteBatch, Writable};
use std::sync::Arc;
use std::fmt::{self, Formatter, Display};
use std::error;

/// Compact task.
pub struct Task {
    engine: Arc<DB>,
    region_id: u64,
    compact_idx: u64,
}

impl Task {
    pub fn new(ps: &PeerStorage, compact_idx: u64) -> Task {
        Task {
            engine: ps.get_engine().clone(),
            region_id: ps.get_region_id(),
            compact_idx: compact_idx,
        }
    }
}

impl Display for Task {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f,
               "Compact Task [region: {}, to: {}]",
               self.region_id,
               self.compact_idx)
    }
}

quick_error! {
    #[derive(Debug)]
    enum Error {
        Other(err: Box<error::Error + Sync + Send>) {
            from()
            cause(err.as_ref())
            description(err.description())
            display("compact failed {:?}", err)
        }
    }
}

pub struct Runner;

impl Runner {
    /// Do the compact job and return the count of log compacted.
    fn compact(&mut self, task: Task) -> Result<u64, Error> {
        let start_key = keys::raft_log_key(task.region_id, 0);
        let mut first_idx = task.compact_idx;
        if let Some((k, _)) = box_try!(task.engine.seek_cf(CF_RAFT, &start_key)) {
            first_idx = box_try!(keys::raft_log_index(&k));
        }
        if first_idx >= task.compact_idx {
            info!("[region {}] no need to compact", task.region_id);
            return Ok(0);
        }
        let wb = WriteBatch::new();
        let handle = box_try!(rocksdb::get_cf_handle(&task.engine, CF_RAFT));
        for idx in first_idx..task.compact_idx {
            let key = keys::raft_log_key(task.region_id, idx);
            box_try!(wb.delete_cf(*handle, &key));
        }
        // It is safe to disable WAL here. If crashed, we can still
        // compact the log after restart.
        box_try!(task.engine.write_without_wal(wb));
        Ok(task.compact_idx - first_idx)
    }
}

impl Runnable<Task> for Runner {
    fn run(&mut self, task: Task) {
        debug!("[region {}] execute compacting log to {}",
               task.region_id,
               task.compact_idx);
        let region_id = task.region_id;
        match self.compact(task) {
            Err(e) => error!("[region {}] failed to compact: {:?}", region_id, e),
            Ok(n) => info!("[region {}] compact {} log entries", region_id, n),
        }
    }
}
<commit_msg>worker: enable WAL (#1073)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use raftstore::store::{PeerStorage, keys};
use raftstore::store::engine::Iterable;
use util::worker::Runnable;
use util::rocksdb;
use storage::CF_RAFT;

use rocksdb::{DB, WriteBatch, Writable};
use std::sync::Arc;
use std::fmt::{self, Formatter, Display};
use std::error;

/// Compact task.
pub struct Task {
    engine: Arc<DB>,
    region_id: u64,
    compact_idx: u64,
}

impl Task {
    pub fn new(ps: &PeerStorage, compact_idx: u64) -> Task {
        Task {
            engine: ps.get_engine().clone(),
            region_id: ps.get_region_id(),
            compact_idx: compact_idx,
        }
    }
}

impl Display for Task {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f,
               "Compact Task [region: {}, to: {}]",
               self.region_id,
               self.compact_idx)
    }
}

quick_error! {
    #[derive(Debug)]
    enum Error {
        Other(err: Box<error::Error + Sync + Send>) {
            from()
            cause(err.as_ref())
            description(err.description())
            display("compact failed {:?}", err)
        }
    }
}

pub struct Runner;

impl Runner {
    /// Do the compact job and return the count of log compacted.
    fn compact(&mut self, task: Task) -> Result<u64, Error> {
        let start_key = keys::raft_log_key(task.region_id, 0);
        let mut first_idx = task.compact_idx;
        if let Some((k, _)) = box_try!(task.engine.seek_cf(CF_RAFT, &start_key)) {
            first_idx = box_try!(keys::raft_log_index(&k));
        }
        if first_idx >= task.compact_idx {
            info!("[region {}] no need to compact", task.region_id);
            return Ok(0);
        }
        let wb = WriteBatch::new();
        let handle = box_try!(rocksdb::get_cf_handle(&task.engine, CF_RAFT));
        for idx in first_idx..task.compact_idx {
            let key = keys::raft_log_key(task.region_id, idx);
            box_try!(wb.delete_cf(*handle, &key));
        }
        // It's not safe to disable WAL here. We may lost data after crashed for unknown reason.
        box_try!(task.engine.write(wb));
        Ok(task.compact_idx - first_idx)
    }
}

impl Runnable<Task> for Runner {
    fn run(&mut self, task: Task) {
        debug!("[region {}] execute compacting log to {}",
               task.region_id,
               task.compact_idx);
        let region_id = task.region_id;
        match self.compact(task) {
            Err(e) => error!("[region {}] failed to compact: {:?}", region_id, e),
            Ok(n) => info!("[region {}] compact {} log entries", region_id, n),
        }
    }
}
<|endoftext|>