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

use ty;

use rustc_data_structures::indexed_vec::Idx;
use serialize;
use std::fmt;
use std::u32;

newtype_index!(CrateNum
    {
        derive[Debug]
        ENCODABLE = custom

        /// Item definitions in the currently-compiled crate would have the CrateNum
        /// LOCAL_CRATE in their DefId.
        const LOCAL_CRATE = 0,

        /// Virtual crate for builtin macros
        // FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
        // `CrateNum`s.
        const BUILTIN_MACROS_CRATE = u32::MAX,

        /// A CrateNum value that indicates that something is wrong.
        const INVALID_CRATE = u32::MAX - 1,

        /// A special CrateNum that we use for the tcx.rcache when decoding from
        /// the incr. comp. cache.
        const RESERVED_FOR_INCR_COMP_CACHE = u32::MAX - 2,
    });

impl CrateNum {
    pub fn new(x: usize) -> CrateNum {
        assert!(x < (u32::MAX as usize));
        CrateNum(x as u32)
    }

    pub fn from_u32(x: u32) -> CrateNum {
        CrateNum(x)
    }

    pub fn as_usize(&self) -> usize {
        self.0 as usize
    }

    pub fn as_u32(&self) -> u32 {
        self.0
    }

    pub fn as_def_id(&self) -> DefId { DefId { krate: *self, index: CRATE_DEF_INDEX } }
}

impl fmt::Display for CrateNum {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl serialize::UseSpecializedEncodable for CrateNum {}
impl serialize::UseSpecializedDecodable for CrateNum {}

/// A DefIndex is an index into the hir-map for a crate, identifying a
/// particular definition. It should really be considered an interned
/// shorthand for a particular DefPath.
///
/// At the moment we are allocating the numerical values of DefIndexes into two
/// ranges: the "low" range (starting at zero) and the "high" range (starting at
/// DEF_INDEX_HI_START). This allows us to allocate the DefIndexes of all
/// item-likes (Items, TraitItems, and ImplItems) into one of these ranges and
/// consequently use a simple array for lookup tables keyed by DefIndex and
/// known to be densely populated. This is especially important for the HIR map.
///
/// Since the DefIndex is mostly treated as an opaque ID, you probably
/// don't have to care about these ranges.
newtype_index!(DefIndex
    {
        ENCODABLE = custom
        DEBUG_FORMAT = custom,

        /// The start of the "high" range of DefIndexes.
        const DEF_INDEX_HI_START = 1 << 31,

        /// The crate root is always assigned index 0 by the AST Map code,
        /// thanks to `NodeCollector::new`.
        const CRATE_DEF_INDEX = 0,
    });

impl fmt::Debug for DefIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "DefIndex({}:{})",
               self.address_space().index(),
               self.as_array_index())
    }
}

impl DefIndex {
    #[inline]
    pub fn from_u32(x: u32) -> DefIndex {
        DefIndex(x)
    }

    #[inline]
    pub fn as_usize(&self) -> usize {
        self.0 as usize
    }

    #[inline]
    pub fn as_u32(&self) -> u32 {
        self.0
    }

    #[inline]
    pub fn address_space(&self) -> DefIndexAddressSpace {
        if self.0 < DEF_INDEX_HI_START.0 {
            DefIndexAddressSpace::Low
        } else {
            DefIndexAddressSpace::High
        }
    }

    /// Converts this DefIndex into a zero-based array index.
    /// This index is the offset within the given "range" of the DefIndex,
    /// that is, if the DefIndex is part of the "high" range, the resulting
    /// index will be (DefIndex - DEF_INDEX_HI_START).
    #[inline]
    pub fn as_array_index(&self) -> usize {
        (self.0 & !DEF_INDEX_HI_START.0) as usize
    }

    pub fn from_array_index(i: usize, address_space: DefIndexAddressSpace) -> DefIndex {
        DefIndex::new(address_space.start() + i)
    }
}

impl serialize::UseSpecializedEncodable for DefIndex {}
impl serialize::UseSpecializedDecodable for DefIndex {}

#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum DefIndexAddressSpace {
    Low = 0,
    High = 1,
}

impl DefIndexAddressSpace {
    #[inline]
    pub fn index(&self) -> usize {
        *self as usize
    }

    #[inline]
    pub fn start(&self) -> usize {
        self.index() * DEF_INDEX_HI_START.as_usize()
    }
}

/// A DefId identifies a particular *definition*, by combining a crate
/// index and a def index.
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, Hash, Copy)]
pub struct DefId {
    pub krate: CrateNum,
    pub index: DefIndex,
}

impl fmt::Debug for DefId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "DefId {{ krate: {:?}, index: {:?}",
               self.krate, self.index)?;

        ty::tls::with_opt(|opt_tcx| {
            if let Some(tcx) = opt_tcx {
                write!(f, " => {}", tcx.def_path_debug_str(*self))?;
            }
            Ok(())
        })?;

        write!(f, " }}")
    }
}

impl DefId {
    /// Make a local `DefId` with the given index.
    #[inline]
    pub fn local(index: DefIndex) -> DefId {
        DefId { krate: LOCAL_CRATE, index: index }
    }

    #[inline]
    pub fn is_local(self) -> bool {
        self.krate == LOCAL_CRATE
    }

     #[inline]
    pub fn to_local(self) -> LocalDefId {
        LocalDefId::from_def_id(self)
    }
}

impl serialize::UseSpecializedEncodable for DefId {}
impl serialize::UseSpecializedDecodable for DefId {}

#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct LocalDefId(DefIndex);

impl LocalDefId {

    #[inline]
    pub fn from_def_id(def_id: DefId) -> LocalDefId {
        assert!(def_id.is_local());
        LocalDefId(def_id.index)
    }

    #[inline]
    pub fn to_def_id(self) -> DefId {
        DefId {
            krate: LOCAL_CRATE,
            index: self.0
        }
    }
}

impl fmt::Debug for LocalDefId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.to_def_id().fmt(f)
    }
}

impl serialize::UseSpecializedEncodable for LocalDefId {}
impl serialize::UseSpecializedDecodable for LocalDefId {}
<commit_msg>Add doc comment for LocalDefId.<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ty;

use rustc_data_structures::indexed_vec::Idx;
use serialize;
use std::fmt;
use std::u32;

newtype_index!(CrateNum
    {
        derive[Debug]
        ENCODABLE = custom

        /// Item definitions in the currently-compiled crate would have the CrateNum
        /// LOCAL_CRATE in their DefId.
        const LOCAL_CRATE = 0,

        /// Virtual crate for builtin macros
        // FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
        // `CrateNum`s.
        const BUILTIN_MACROS_CRATE = u32::MAX,

        /// A CrateNum value that indicates that something is wrong.
        const INVALID_CRATE = u32::MAX - 1,

        /// A special CrateNum that we use for the tcx.rcache when decoding from
        /// the incr. comp. cache.
        const RESERVED_FOR_INCR_COMP_CACHE = u32::MAX - 2,
    });

impl CrateNum {
    pub fn new(x: usize) -> CrateNum {
        assert!(x < (u32::MAX as usize));
        CrateNum(x as u32)
    }

    pub fn from_u32(x: u32) -> CrateNum {
        CrateNum(x)
    }

    pub fn as_usize(&self) -> usize {
        self.0 as usize
    }

    pub fn as_u32(&self) -> u32 {
        self.0
    }

    pub fn as_def_id(&self) -> DefId { DefId { krate: *self, index: CRATE_DEF_INDEX } }
}

impl fmt::Display for CrateNum {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl serialize::UseSpecializedEncodable for CrateNum {}
impl serialize::UseSpecializedDecodable for CrateNum {}

/// A DefIndex is an index into the hir-map for a crate, identifying a
/// particular definition. It should really be considered an interned
/// shorthand for a particular DefPath.
///
/// At the moment we are allocating the numerical values of DefIndexes into two
/// ranges: the "low" range (starting at zero) and the "high" range (starting at
/// DEF_INDEX_HI_START). This allows us to allocate the DefIndexes of all
/// item-likes (Items, TraitItems, and ImplItems) into one of these ranges and
/// consequently use a simple array for lookup tables keyed by DefIndex and
/// known to be densely populated. This is especially important for the HIR map.
///
/// Since the DefIndex is mostly treated as an opaque ID, you probably
/// don't have to care about these ranges.
newtype_index!(DefIndex
    {
        ENCODABLE = custom
        DEBUG_FORMAT = custom,

        /// The start of the "high" range of DefIndexes.
        const DEF_INDEX_HI_START = 1 << 31,

        /// The crate root is always assigned index 0 by the AST Map code,
        /// thanks to `NodeCollector::new`.
        const CRATE_DEF_INDEX = 0,
    });

impl fmt::Debug for DefIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "DefIndex({}:{})",
               self.address_space().index(),
               self.as_array_index())
    }
}

impl DefIndex {
    #[inline]
    pub fn from_u32(x: u32) -> DefIndex {
        DefIndex(x)
    }

    #[inline]
    pub fn as_usize(&self) -> usize {
        self.0 as usize
    }

    #[inline]
    pub fn as_u32(&self) -> u32 {
        self.0
    }

    #[inline]
    pub fn address_space(&self) -> DefIndexAddressSpace {
        if self.0 < DEF_INDEX_HI_START.0 {
            DefIndexAddressSpace::Low
        } else {
            DefIndexAddressSpace::High
        }
    }

    /// Converts this DefIndex into a zero-based array index.
    /// This index is the offset within the given "range" of the DefIndex,
    /// that is, if the DefIndex is part of the "high" range, the resulting
    /// index will be (DefIndex - DEF_INDEX_HI_START).
    #[inline]
    pub fn as_array_index(&self) -> usize {
        (self.0 & !DEF_INDEX_HI_START.0) as usize
    }

    pub fn from_array_index(i: usize, address_space: DefIndexAddressSpace) -> DefIndex {
        DefIndex::new(address_space.start() + i)
    }
}

impl serialize::UseSpecializedEncodable for DefIndex {}
impl serialize::UseSpecializedDecodable for DefIndex {}

#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum DefIndexAddressSpace {
    Low = 0,
    High = 1,
}

impl DefIndexAddressSpace {
    #[inline]
    pub fn index(&self) -> usize {
        *self as usize
    }

    #[inline]
    pub fn start(&self) -> usize {
        self.index() * DEF_INDEX_HI_START.as_usize()
    }
}

/// A DefId identifies a particular *definition*, by combining a crate
/// index and a def index.
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, Hash, Copy)]
pub struct DefId {
    pub krate: CrateNum,
    pub index: DefIndex,
}

impl fmt::Debug for DefId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "DefId {{ krate: {:?}, index: {:?}",
               self.krate, self.index)?;

        ty::tls::with_opt(|opt_tcx| {
            if let Some(tcx) = opt_tcx {
                write!(f, " => {}", tcx.def_path_debug_str(*self))?;
            }
            Ok(())
        })?;

        write!(f, " }}")
    }
}

impl DefId {
    /// Make a local `DefId` with the given index.
    #[inline]
    pub fn local(index: DefIndex) -> DefId {
        DefId { krate: LOCAL_CRATE, index: index }
    }

    #[inline]
    pub fn is_local(self) -> bool {
        self.krate == LOCAL_CRATE
    }

    #[inline]
    pub fn to_local(self) -> LocalDefId {
        LocalDefId::from_def_id(self)
    }
}

impl serialize::UseSpecializedEncodable for DefId {}
impl serialize::UseSpecializedDecodable for DefId {}

/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
/// we encode this information in the type, we can ensure at compile time that
/// no DefIds from upstream crates get thrown into the mix. There are quite a
/// few cases where we know that only DefIds from the local crate are expected
/// and a DefId from a different crate would signify a bug somewhere. This
/// is when LocalDefId comes in handy.
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct LocalDefId(DefIndex);

impl LocalDefId {

    #[inline]
    pub fn from_def_id(def_id: DefId) -> LocalDefId {
        assert!(def_id.is_local());
        LocalDefId(def_id.index)
    }

    #[inline]
    pub fn to_def_id(self) -> DefId {
        DefId {
            krate: LOCAL_CRATE,
            index: self.0
        }
    }
}

impl fmt::Debug for LocalDefId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.to_def_id().fmt(f)
    }
}

impl serialize::UseSpecializedEncodable for LocalDefId {}
impl serialize::UseSpecializedDecodable for LocalDefId {}
<|endoftext|>


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

use build::{Location, ScopeAuxiliaryVec};
use rustc::hir;
use rustc::mir::repr::*;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use syntax::ast::NodeId;
use syntax::codemap::Span;

const INDENT: &'static str = "    ";

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          disambiguator: &Display,
                          src: MirSource,
                          mir: &Mir<'tcx>,
                          auxiliary: Option<&ScopeAuxiliaryVec>) {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return,
        Some(ref filters) => filters,
    };
    let node_id = src.item_id();
    let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
    let is_matched =
        filters.split("&")
               .any(|filter| {
                   filter == "all" ||
                       pass_name.contains(filter) ||
                       node_path.contains(filter)
               });
    if !is_matched {
        return;
    }

    let file_name = format!("rustc.node{}.{}.{}.mir",
                            node_id, pass_name, disambiguator);
    let _ = fs::File::create(&file_name).and_then(|mut file| {
        try!(writeln!(file, "// MIR for `{}`", node_path));
        try!(writeln!(file, "// node_id = {}", node_id));
        try!(writeln!(file, "// pass_name = {}", pass_name));
        try!(writeln!(file, "// disambiguator = {}", disambiguator));
        try!(writeln!(file, ""));
        try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary));
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                         iter: I,
                                         w: &mut Write)
                                         -> io::Result<()>
    where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
{
    for (&id, mir) in iter {
        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w, None)?;

        for (i, mir) in mir.promoted.iter().enumerate() {
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
        }
    }
    Ok(())
}

enum Annotation {
    EnterScope(ScopeId),
    ExitScope(ScopeId),
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write,
                              auxiliary: Option<&ScopeAuxiliaryVec>)
                              -> io::Result<()> {
    // compute scope/entry exit annotations
    let mut annotations = FnvHashMap();
    if let Some(auxiliary) = auxiliary {
        for (index, auxiliary) in auxiliary.vec.iter().enumerate() {
            let scope_id = ScopeId::new(index);

            annotations.entry(auxiliary.dom)
                       .or_insert(vec![])
                       .push(Annotation::EnterScope(scope_id));

            for &loc in &auxiliary.postdoms {
                annotations.entry(loc)
                           .or_insert(vec![])
                           .push(Annotation::ExitScope(scope_id));
            }
        }
    }

    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.all_basic_blocks() {
        write_basic_block(tcx, block, mir, w, &annotations)?;
    }

    // construct a scope tree and write it out
    let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap();
    for (index, scope_data) in mir.scopes.iter().enumerate() {
        scope_tree.entry(scope_data.parent_scope)
                  .or_insert(vec![])
                  .push(ScopeId::new(index));
    }
    write_scope_tree(tcx, mir, auxiliary, &scope_tree, w, None, 1)?;

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write,
                     annotations: &FnvHashMap<Location, Vec<Annotation>>)
                     -> io::Result<()> {
    let data = mir.basic_block_data(block);

    // Basic block label at the top.
    writeln!(w, "\n{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        if let Some(ref annotations) = annotations.get(&current_location) {
            for annotation in annotations.iter() {
                match *annotation {
                    Annotation::EnterScope(id) =>
                        writeln!(w, "{0}{0}// Enter Scope({1})",
                                 INDENT, id.index())?,
                    Annotation::ExitScope(id) =>
                        writeln!(w, "{0}{0}// Exit Scope({1})",
                                 INDENT, id.index())?,
                }
            }
        }

        writeln!(w, "{0}{0}{1:?}; // {2}",
                 INDENT,
                 statement,
                 comment(tcx, statement.scope, statement.span))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    writeln!(w, "{0}{0}{1:?}; // {2}",
             INDENT,
             data.terminator().kind,
             comment(tcx, data.terminator().scope, data.terminator().span))?;

    writeln!(w, "{}}}", INDENT)
}

fn comment(tcx: TyCtxt, scope: ScopeId, span: Span) -> String {
    format!("Scope({}) at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    auxiliary: Option<&ScopeAuxiliaryVec>,
                    scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>,
                    w: &mut Write,
                    parent: Option<ScopeId>,
                    depth: usize)
                    -> io::Result<()> {
    for &child in scope_tree.get(&parent).unwrap_or(&vec![]) {
        let indent = depth * INDENT.len();
        let data = &mir.scopes[child];
        assert_eq!(data.parent_scope, parent);
        writeln!(w, "{0:1$}Scope({2}) {{", "", indent, child.index())?;

        let indent = indent + INDENT.len();
        if let Some(parent) = parent {
            writeln!(w, "{0:1$}Parent: Scope({2})", "", indent, parent.index())?;
        }

        if let Some(auxiliary) = auxiliary {
            let extent = auxiliary[child].extent;
            let data = tcx.region_maps.code_extent_data(extent);
            writeln!(w, "{0:1$}Extent: {2:?}", "", indent, data)?;
        }

        write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
                         Some(child), depth + 1)?;
    }
    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "promoted{} in", i)?
    }

    write!(w, " {}", tcx.node_path_str(src.item_id()))?;

    if let MirSource::Fn(_) = src {
        write!(w, "(")?;

        // fn argument types.
        for (i, arg) in mir.arg_decls.iter().enumerate() {
            if i > 0 {
                write!(w, ", ")?;
            }
            write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
        }

        write!(w, ") -> ")?;

        // fn return type.
        match mir.return_ty {
            ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
            ty::FnOutput::FnDiverging => write!(w, "!")?,
        }
    } else {
        assert!(mir.arg_decls.is_empty());
        write!(w, ": {} =", mir.return_ty.unwrap())?;
    }

    writeln!(w, " {{")?;

    // User variable types (including the user's name in a comment).
    for (i, var) in mir.var_decls.iter().enumerate() {
        write!(w, "{}let ", INDENT)?;
        if var.mutability == Mutability::Mut {
            write!(w, "mut ")?;
        }
        writeln!(w, "{:?}: {}; // {} in {}",
                 Lvalue::Var(i as u32),
                 var.ty,
                 var.name,
                 comment(tcx, var.scope, var.span))?;
    }

    // Compiler-introduced temporary types.
    for (i, temp) in mir.temp_decls.iter().enumerate() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?;
    }

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

use build::{Location, ScopeAuxiliaryVec};
use rustc::hir;
use rustc::mir::repr::*;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use syntax::ast::NodeId;
use syntax::codemap::Span;

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 50;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          disambiguator: &Display,
                          src: MirSource,
                          mir: &Mir<'tcx>,
                          auxiliary: Option<&ScopeAuxiliaryVec>) {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return,
        Some(ref filters) => filters,
    };
    let node_id = src.item_id();
    let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
    let is_matched =
        filters.split("&")
               .any(|filter| {
                   filter == "all" ||
                       pass_name.contains(filter) ||
                       node_path.contains(filter)
               });
    if !is_matched {
        return;
    }

    let file_name = format!("rustc.node{}.{}.{}.mir",
                            node_id, pass_name, disambiguator);
    let _ = fs::File::create(&file_name).and_then(|mut file| {
        try!(writeln!(file, "// MIR for `{}`", node_path));
        try!(writeln!(file, "// node_id = {}", node_id));
        try!(writeln!(file, "// pass_name = {}", pass_name));
        try!(writeln!(file, "// disambiguator = {}", disambiguator));
        try!(writeln!(file, ""));
        try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary));
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                         iter: I,
                                         w: &mut Write)
                                         -> io::Result<()>
    where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
{
    let mut first = true;
    for (&id, mir) in iter {
        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w, None)?;

        for (i, mir) in mir.promoted.iter().enumerate() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
        }
    }
    Ok(())
}

enum Annotation {
    EnterScope(ScopeId),
    ExitScope(ScopeId),
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write,
                              auxiliary: Option<&ScopeAuxiliaryVec>)
                              -> io::Result<()> {
    // compute scope/entry exit annotations
    let mut annotations = FnvHashMap();
    if let Some(auxiliary) = auxiliary {
        for (index, auxiliary) in auxiliary.vec.iter().enumerate() {
            let scope_id = ScopeId::new(index);

            annotations.entry(auxiliary.dom)
                       .or_insert(vec![])
                       .push(Annotation::EnterScope(scope_id));

            for &loc in &auxiliary.postdoms {
                annotations.entry(loc)
                           .or_insert(vec![])
                           .push(Annotation::ExitScope(scope_id));
            }
        }
    }

    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.all_basic_blocks() {
        write_basic_block(tcx, block, mir, w, &annotations)?;
    }

    // construct a scope tree and write it out
    let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap();
    for (index, scope_data) in mir.scopes.iter().enumerate() {
        scope_tree.entry(scope_data.parent_scope)
                  .or_insert(vec![])
                  .push(ScopeId::new(index));
    }

    writeln!(w, "{}scope tree:", INDENT)?;
    write_scope_tree(tcx, mir, auxiliary, &scope_tree, w, None, 1)?;

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write,
                     annotations: &FnvHashMap<Location, Vec<Annotation>>)
                     -> io::Result<()> {
    let data = mir.basic_block_data(block);

    // Basic block label at the top.
    writeln!(w, "{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        if let Some(ref annotations) = annotations.get(&current_location) {
            for annotation in annotations.iter() {
                match *annotation {
                    Annotation::EnterScope(id) =>
                        writeln!(w, "{0}{0}// Enter Scope({1})",
                                 INDENT, id.index())?,
                    Annotation::ExitScope(id) =>
                        writeln!(w, "{0}{0}// Exit Scope({1})",
                                 INDENT, id.index())?,
                }
            }
        }

        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.scope, statement.span))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().scope, data.terminator().span))?;

    writeln!(w, "{}}}\n", INDENT)
}

fn comment(tcx: TyCtxt, scope: ScopeId, span: Span) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    auxiliary: Option<&ScopeAuxiliaryVec>,
                    scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>,
                    w: &mut Write,
                    parent: Option<ScopeId>,
                    depth: usize)
                    -> io::Result<()> {
    for &child in scope_tree.get(&parent).unwrap_or(&vec![]) {
        let indent = depth * INDENT.len();
        let data = &mir.scopes[child];
        assert_eq!(data.parent_scope, parent);
        write!(w, "{0:1$}{2}", "", indent, child.index())?;

        let indent = indent + INDENT.len();

        if let Some(auxiliary) = auxiliary {
            let extent = auxiliary[child].extent;
            let data = tcx.region_maps.code_extent_data(extent);
            writeln!(w, "{0:1$}Extent: {2:?}", "", indent, data)?;
        }

        if scope_tree.get(&Some(child)).map(Vec::is_empty).unwrap_or(true) {
            // No child scopes, skip the braces
            writeln!(w, "")?;
        } else {
            writeln!(w, " {{")?;
            write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
                             Some(child), depth + 1)?;

            writeln!(w, "{0:1$}}}", "", indent - INDENT.len())?;
        }
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "promoted{} in", i)?
    }

    write!(w, " {}", tcx.node_path_str(src.item_id()))?;

    if let MirSource::Fn(_) = src {
        write!(w, "(")?;

        // fn argument types.
        for (i, arg) in mir.arg_decls.iter().enumerate() {
            if i > 0 {
                write!(w, ", ")?;
            }
            write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
        }

        write!(w, ") -> ")?;

        // fn return type.
        match mir.return_ty {
            ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
            ty::FnOutput::FnDiverging => write!(w, "!")?,
        }
    } else {
        assert!(mir.arg_decls.is_empty());
        write!(w, ": {} =", mir.return_ty.unwrap())?;
    }

    writeln!(w, " {{")?;

    // User variable types (including the user's name in a comment).
    for (i, var) in mir.var_decls.iter().enumerate() {
        let mut_str = if var.mutability == Mutability::Mut {
            "mut "
        } else {
            ""
        };

        let indented_var = format!("{}let {}{:?}: {};",
                                   INDENT,
                                   mut_str,
                                   Lvalue::Var(i as u32),
                                   var.ty);
        writeln!(w, "{0:1$} // \"{2}\" in {3}",
                 indented_var,
                 ALIGN,
                 var.name,
                 comment(tcx, var.scope, var.span))?;
    }

    // Compiler-introduced temporary types.
    for (i, temp) in mir.temp_decls.iter().enumerate() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?;
    }

    // Wrote any declaration? Add an empty line before the first block is printed.
    if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
        writeln!(w, "")?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::{Show,Formatter};
use std::collections::HashMap;
use semver::Version;
use serialize::{Encoder,Decoder,Encodable,Decodable};
use core::{
    Dependency,
    NameVer,
    Package,
    Summary
};
use core::dependency::SerializedDependency;
use util::{CargoResult,Require,toml_error,simple_human};
use toml;
use toml::{Table, ParseError};

#[deriving(PartialEq,Clone)]
pub struct Manifest {
    summary: Summary,
    authors: Vec<String>,
    targets: Vec<Target>,
    target_dir: Path,
}

impl Show for Manifest {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Manifest({}, authors={}, targets={}, target_dir={})", self.summary, self.authors, self.targets, self.target_dir.display())
    }
}

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

impl<E, S: Encoder<E>> Encodable<S, E> for Manifest {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        SerializedManifest {
            name: self.summary.get_name().to_str(),
            version: self.summary.get_version().to_str(),
            dependencies: self.summary.get_dependencies().iter().map(|d| SerializedDependency::from_dependency(d)).collect(),
            authors: self.authors.clone(),
            targets: self.targets.clone(),
            target_dir: self.target_dir.display().to_str()
        }.encode(s)
    }
}

#[deriving(Show,Clone,PartialEq,Encodable)]
pub enum TargetKind {
    LibTarget,
    BinTarget
}

#[deriving(Clone,PartialEq)]
pub struct Target {
    kind: TargetKind,
    name: String,
    path: Path
}

#[deriving(Encodable)]
pub struct SerializedTarget {
    kind: &'static str,
    name: String,
    path: String
}

impl<E, S: Encoder<E>> Encodable<S, E> for Target {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let kind = match self.kind {
            LibTarget => "lib",
            BinTarget => "bin"
        };

        SerializedTarget {
            kind: kind,
            name: self.name.clone(),
            path: self.path.display().to_str()
        }.encode(s)
    }
}

impl Show for Target {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}(name={}, path={})", self.kind, self.name, self.path.display())
    }
}

impl Manifest {
    pub fn new(summary: &Summary, targets: &[Target], target_dir: &Path) -> Manifest {
        Manifest {
            summary: summary.clone(),
            authors: Vec::new(),
            targets: Vec::from_slice(targets),
            target_dir: target_dir.clone()
        }
    }

    pub fn get_summary<'a>(&'a self) -> &'a Summary {
        &self.summary
    }

    pub fn get_name<'a>(&'a self) -> &'a str {
        self.get_summary().get_name_ver().get_name()
    }

    pub fn get_version<'a>(&'a self) -> &'a Version {
        self.get_summary().get_name_ver().get_version()
    }

    pub fn get_authors<'a>(&'a self) -> &'a [String] {
        self.authors.as_slice()
    }

    pub fn get_dependencies<'a>(&'a self) -> &'a [Dependency] {
        self.get_summary().get_dependencies()
    }

    pub fn get_targets<'a>(&'a self) -> &'a [Target] {
        self.targets.as_slice()
    }

    pub fn get_target_dir<'a>(&'a self) -> &'a Path {
        &self.target_dir
    }
}

impl Target {
    pub fn lib_target(name: &str, path: &Path) -> Target {
        Target {
            kind: LibTarget,
            name: name.to_str(),
            path: path.clone()
        }
    }

    pub fn bin_target(name: &str, path: &Path) -> Target {
        Target {
            kind: BinTarget,
            name: name.to_str(),
            path: path.clone()
        }
    }

    pub fn get_path<'a>(&'a self) -> &'a Path {
        &self.path
    }

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

    pub fn is_bin(&self) -> bool {
        match self.kind {
            BinTarget => true,
            _ => false
        }
    }

    pub fn rustc_crate_type(&self) -> &'static str {
        match self.kind {
            LibTarget => "lib",
            BinTarget => "bin"
        }
    }
}

/*
 *
 * ===== Serialized =====
 *
 */

type TomlLibTarget = TomlTarget;
type TomlBinTarget = TomlTarget;

#[deriving(Decodable,Encodable,PartialEq,Clone,Show)]
pub struct Project {
    pub name: String,
    pub version: String,
    pub authors: Vec<String>
}

/*
 * TODO: Make all struct fields private
 */

#[deriving(Encodable,PartialEq,Clone,Show)]
pub enum TomlDependency {
    SimpleDep(String),
    DetailedDep(HashMap<String, String>)
}

#[deriving(Encodable,PartialEq,Clone)]
pub struct TomlManifest {
    project: Box<Project>,
    lib: Option<Vec<TomlLibTarget>>,
    bin: Option<Vec<TomlBinTarget>>,
    dependencies: Option<HashMap<String, TomlDependency>>,
}

impl TomlManifest {
    pub fn from_toml(root: toml::Value) -> CargoResult<TomlManifest> {
        fn decode<T: Decodable<toml::Decoder,toml::Error>>(root: &toml::Value, path: &str) -> Result<T, toml::Error> {
            let root = match root.lookup(path) {
                Some(val) => val,
                None => return Err(toml::ParseError)
            };
            toml::from_toml(root.clone())
        }

        let project = try!(decode(&root, "project").map_err(|e| toml_error("ZOMG", e)));
        let lib = decode(&root, "lib").ok();
        let bin = decode(&root, "bin").ok();

        let deps = root.lookup("dependencies");

        let deps = match deps {
            Some(deps) => {
                let table = try!(deps.get_table().require(simple_human("dependencies must be a table"))).clone();

                let mut deps: HashMap<String, TomlDependency> = HashMap::new();

                for (k, v) in table.iter() {
                    match v {
                        &toml::String(ref string) => { deps.insert(k.clone(), SimpleDep(string.clone())); },
                        &toml::Table(ref table) => {
                            let mut details = HashMap::<String, String>::new();

                            for (k, v) in table.iter() {
                                let v = try!(v.get_str()
                                             .require(simple_human("dependency values must be string")));

                                details.insert(k.clone(), v.clone());
                            }

                            deps.insert(k.clone(), DetailedDep(details));
                        },
                        _ => ()
                    }
                }

                Some(deps)
            },
            None => None
        };

        Ok(TomlManifest { project: box project, lib: lib, bin: bin, dependencies: deps })
    }

    pub fn to_package(&self, path: &str) -> CargoResult<Package> {
        // TODO: Convert hte argument to take a Path
        let path = Path::new(path);

        // Get targets
        let targets = normalize(self.lib.as_ref().map(|l| l.as_slice()), self.bin.as_ref().map(|b| b.as_slice()));

        if targets.is_empty() {
            debug!("manifest has no build targets; project={}", self.project);
        }

        let mut deps = Vec::new();

        // Collect the deps
        match self.dependencies {
            Some(ref dependencies) => {
                for (n, v) in dependencies.iter() {
                    let version = match *v {
                        SimpleDep(ref string) => string,
                        DetailedDep(ref map) => try!(map.find_equiv(&"version")
                                                     .require(simple_human("dependencies must include a version")))
                    };

                    deps.push(try!(Dependency::parse(n.as_slice(), version.as_slice())))
                }
            }
            None => ()
        }

        // TODO: https://github.com/mozilla/rust/issues/14049
        let root = Path::new(path.dirname());

        Ok(Package::new(
            &Manifest::new(
                &Summary::new(&self.project.to_name_ver(), deps.as_slice()),
                targets.as_slice(),
                &Path::new("target")),
            &root))
    }
}

impl Project {
    fn to_name_ver(&self) -> NameVer {
        NameVer::new(self.name.as_slice(), self.version.as_slice())
    }
}

#[deriving(Decodable,Encodable,PartialEq,Clone,Show)]
struct TomlTarget {
    name: String,
    path: Option<String>
}

fn normalize(lib: Option<&[TomlLibTarget]>, bin: Option<&[TomlBinTarget]>) -> Vec<Target> {
    log!(4, "normalizing toml targets; lib={}; bin={}", lib, bin);

    fn lib_targets(dst: &mut Vec<Target>, libs: &[TomlLibTarget]) {
        let l = &libs[0];
        let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name));
        dst.push(Target::lib_target(l.name.as_slice(), &Path::new(path)));
    }

    fn bin_targets(dst: &mut Vec<Target>, bins: &[TomlBinTarget], default: |&TomlBinTarget| -> String) {
        for bin in bins.iter() {
            let path = bin.path.clone().unwrap_or_else(|| default(bin));
            dst.push(Target::bin_target(bin.name.as_slice(), &Path::new(path)));
        }
    }

    let mut ret = Vec::new();

    match (lib, bin) {
        (Some(ref libs), Some(ref bins)) => {
            lib_targets(&mut ret, libs.as_slice());
            bin_targets(&mut ret, bins.as_slice(), |bin| format!("src/bin/{}.rs", bin.name));
        },
        (Some(ref libs), None) => {
            lib_targets(&mut ret, libs.as_slice());
        },
        (None, Some(ref bins)) => {
            bin_targets(&mut ret, bins.as_slice(), |bin| format!("src/{}.rs", bin.name));
        },
        (None, None) => ()
    }

    ret
}
<commit_msg>Validate dependency version on parse, not usage<commit_after>use std::fmt;
use std::fmt::{Show,Formatter};
use std::collections::HashMap;
use semver::Version;
use serialize::{Encoder,Decoder,Encodable,Decodable};
use core::{
    Dependency,
    NameVer,
    Package,
    Summary
};
use core::dependency::SerializedDependency;
use util::{CargoResult,Require,toml_error,simple_human};
use toml;
use toml::{Table, ParseError};

#[deriving(PartialEq,Clone)]
pub struct Manifest {
    summary: Summary,
    authors: Vec<String>,
    targets: Vec<Target>,
    target_dir: Path,
}

impl Show for Manifest {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Manifest({}, authors={}, targets={}, target_dir={})", self.summary, self.authors, self.targets, self.target_dir.display())
    }
}

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

impl<E, S: Encoder<E>> Encodable<S, E> for Manifest {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        SerializedManifest {
            name: self.summary.get_name().to_str(),
            version: self.summary.get_version().to_str(),
            dependencies: self.summary.get_dependencies().iter().map(|d| SerializedDependency::from_dependency(d)).collect(),
            authors: self.authors.clone(),
            targets: self.targets.clone(),
            target_dir: self.target_dir.display().to_str()
        }.encode(s)
    }
}

#[deriving(Show,Clone,PartialEq,Encodable)]
pub enum TargetKind {
    LibTarget,
    BinTarget
}

#[deriving(Clone,PartialEq)]
pub struct Target {
    kind: TargetKind,
    name: String,
    path: Path
}

#[deriving(Encodable)]
pub struct SerializedTarget {
    kind: &'static str,
    name: String,
    path: String
}

impl<E, S: Encoder<E>> Encodable<S, E> for Target {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let kind = match self.kind {
            LibTarget => "lib",
            BinTarget => "bin"
        };

        SerializedTarget {
            kind: kind,
            name: self.name.clone(),
            path: self.path.display().to_str()
        }.encode(s)
    }
}

impl Show for Target {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}(name={}, path={})", self.kind, self.name, self.path.display())
    }
}

impl Manifest {
    pub fn new(summary: &Summary, targets: &[Target], target_dir: &Path) -> Manifest {
        Manifest {
            summary: summary.clone(),
            authors: Vec::new(),
            targets: Vec::from_slice(targets),
            target_dir: target_dir.clone()
        }
    }

    pub fn get_summary<'a>(&'a self) -> &'a Summary {
        &self.summary
    }

    pub fn get_name<'a>(&'a self) -> &'a str {
        self.get_summary().get_name_ver().get_name()
    }

    pub fn get_version<'a>(&'a self) -> &'a Version {
        self.get_summary().get_name_ver().get_version()
    }

    pub fn get_authors<'a>(&'a self) -> &'a [String] {
        self.authors.as_slice()
    }

    pub fn get_dependencies<'a>(&'a self) -> &'a [Dependency] {
        self.get_summary().get_dependencies()
    }

    pub fn get_targets<'a>(&'a self) -> &'a [Target] {
        self.targets.as_slice()
    }

    pub fn get_target_dir<'a>(&'a self) -> &'a Path {
        &self.target_dir
    }
}

impl Target {
    pub fn lib_target(name: &str, path: &Path) -> Target {
        Target {
            kind: LibTarget,
            name: name.to_str(),
            path: path.clone()
        }
    }

    pub fn bin_target(name: &str, path: &Path) -> Target {
        Target {
            kind: BinTarget,
            name: name.to_str(),
            path: path.clone()
        }
    }

    pub fn get_path<'a>(&'a self) -> &'a Path {
        &self.path
    }

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

    pub fn is_bin(&self) -> bool {
        match self.kind {
            BinTarget => true,
            _ => false
        }
    }

    pub fn rustc_crate_type(&self) -> &'static str {
        match self.kind {
            LibTarget => "lib",
            BinTarget => "bin"
        }
    }
}

/*
 *
 * ===== Serialized =====
 *
 */

type TomlLibTarget = TomlTarget;
type TomlBinTarget = TomlTarget;

#[deriving(Decodable,Encodable,PartialEq,Clone,Show)]
pub struct Project {
    pub name: String,
    pub version: String,
    pub authors: Vec<String>
}

/*
 * TODO: Make all struct fields private
 */

#[deriving(Encodable,PartialEq,Clone,Show)]
pub enum TomlDependency {
    SimpleDep(String),
    DetailedDep(DetailedTomlDependency)
}

#[deriving(Encodable,PartialEq,Clone,Show)]
pub struct DetailedTomlDependency {
    version: String,
    other: HashMap<String, String>
}

#[deriving(Encodable,PartialEq,Clone)]
pub struct TomlManifest {
    project: Box<Project>,
    lib: Option<Vec<TomlLibTarget>>,
    bin: Option<Vec<TomlBinTarget>>,
    dependencies: Option<HashMap<String, TomlDependency>>,
}

impl TomlManifest {
    pub fn from_toml(root: toml::Value) -> CargoResult<TomlManifest> {
        fn decode<T: Decodable<toml::Decoder,toml::Error>>(root: &toml::Value, path: &str) -> Result<T, toml::Error> {
            let root = match root.lookup(path) {
                Some(val) => val,
                None => return Err(toml::ParseError)
            };
            toml::from_toml(root.clone())
        }

        let project = try!(decode(&root, "project").map_err(|e| toml_error("ZOMG", e)));
        let lib = decode(&root, "lib").ok();
        let bin = decode(&root, "bin").ok();

        let deps = root.lookup("dependencies");

        let deps = match deps {
            Some(deps) => {
                let table = try!(deps.get_table().require(simple_human("dependencies must be a table"))).clone();

                let mut deps: HashMap<String, TomlDependency> = HashMap::new();

                for (k, v) in table.iter() {
                    match v {
                        &toml::String(ref string) => { deps.insert(k.clone(), SimpleDep(string.clone())); },
                        &toml::Table(ref table) => {
                            let mut details = HashMap::<String, String>::new();

                            for (k, v) in table.iter() {
                                let v = try!(v.get_str()
                                             .require(simple_human("dependency values must be string")));

                                details.insert(k.clone(), v.clone());
                            }

                            let version = try!(details.find_equiv(&"version")
                                               .require(simple_human("dependencies must include a version"))).clone();

                            deps.insert(k.clone(), DetailedDep(DetailedTomlDependency {
                                version: version,
                                other: details
                            }));
                        },
                        _ => ()
                    }
                }

                Some(deps)
            },
            None => None
        };

        Ok(TomlManifest { project: box project, lib: lib, bin: bin, dependencies: deps })
    }

    pub fn to_package(&self, path: &str) -> CargoResult<Package> {
        // TODO: Convert hte argument to take a Path
        let path = Path::new(path);

        // Get targets
        let targets = normalize(self.lib.as_ref().map(|l| l.as_slice()), self.bin.as_ref().map(|b| b.as_slice()));

        if targets.is_empty() {
            debug!("manifest has no build targets; project={}", self.project);
        }

        let mut deps = Vec::new();

        // Collect the deps
        match self.dependencies {
            Some(ref dependencies) => {
                for (n, v) in dependencies.iter() {
                    let version = match *v {
                        SimpleDep(ref string) => string.clone(),
                        DetailedDep(ref details) => details.version.clone()
                    };

                    deps.push(try!(Dependency::parse(n.as_slice(), version.as_slice())))
                }
            }
            None => ()
        }

        // TODO: https://github.com/mozilla/rust/issues/14049
        let root = Path::new(path.dirname());

        Ok(Package::new(
            &Manifest::new(
                &Summary::new(&self.project.to_name_ver(), deps.as_slice()),
                targets.as_slice(),
                &Path::new("target")),
            &root))
    }
}

impl Project {
    fn to_name_ver(&self) -> NameVer {
        NameVer::new(self.name.as_slice(), self.version.as_slice())
    }
}

#[deriving(Decodable,Encodable,PartialEq,Clone,Show)]
struct TomlTarget {
    name: String,
    path: Option<String>
}

fn normalize(lib: Option<&[TomlLibTarget]>, bin: Option<&[TomlBinTarget]>) -> Vec<Target> {
    log!(4, "normalizing toml targets; lib={}; bin={}", lib, bin);

    fn lib_targets(dst: &mut Vec<Target>, libs: &[TomlLibTarget]) {
        let l = &libs[0];
        let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name));
        dst.push(Target::lib_target(l.name.as_slice(), &Path::new(path)));
    }

    fn bin_targets(dst: &mut Vec<Target>, bins: &[TomlBinTarget], default: |&TomlBinTarget| -> String) {
        for bin in bins.iter() {
            let path = bin.path.clone().unwrap_or_else(|| default(bin));
            dst.push(Target::bin_target(bin.name.as_slice(), &Path::new(path)));
        }
    }

    let mut ret = Vec::new();

    match (lib, bin) {
        (Some(ref libs), Some(ref bins)) => {
            lib_targets(&mut ret, libs.as_slice());
            bin_targets(&mut ret, bins.as_slice(), |bin| format!("src/bin/{}.rs", bin.name));
        },
        (Some(ref libs), None) => {
            lib_targets(&mut ret, libs.as_slice());
        },
        (None, Some(ref bins)) => {
            bin_targets(&mut ret, bins.as_slice(), |bin| format!("src/{}.rs", bin.name));
        },
        (None, None) => ()
    }

    ret
}
<|endoftext|>


<commit_before>use into::IntoError;

#[macro_export]
macro_rules! generate_error_imports {
    () => {
        use std::error::Error;
        use std::fmt::Error as FmtError;
        use std::fmt::{Display, Formatter};
    }
}

#[macro_export]
macro_rules! generate_error_module {
    ( $exprs:item ) => {
        pub mod error {
            generate_error_imports!();
            $exprs
        }
    }
}

#[macro_export]
macro_rules! generate_error_types {
    (
        $name: ident,
        $kindname: ident,
        $($kind:ident => $string:expr),*
    ) => {
        #[derive(Clone, Copy, Debug, PartialEq)]
        pub enum $kindname {
            $( $kind ),*
        }

        impl Display for $kindname {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                let s = match *self {
                    $( $kindname::$kind => $string ),*
                };
                try!(write!(fmt, "{}", s));
                Ok(())
            }

        }

        impl IntoError for $kindname {
            type Target = $name;

            fn into_error(self) -> Self::Target {
                $name::new(self, None)
            }

            fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target {
                $name::new(self, Some(cause))
            }

        }

        #[derive(Debug)]
        pub struct $name {
            err_type: $kindname,
            cause: Option<Box<Error>>,
        }

        impl $name {

            pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name {
                $name {
                    err_type: errtype,
                    cause: cause,
                }
            }

            pub fn err_type(&self) -> $kindname {
                self.err_type
            }

        }

        impl Display for $name {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                try!(write!(fmt, "[{}]", self.err_type));
                Ok(())
            }

        }

        impl Error for $name {

            fn description(&self) -> &str {
                match self.err_type {
                    $( $kindname::$kind => $string ),*
                }
            }

            fn cause(&self) -> Option<&Error> {
                self.cause.as_ref().map(|e| &**e)
            }

        }

    }
}

#[cfg(test)]
mod test {

    generate_error_module!(
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    );

    #[test]
    fn test_a() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_b() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_ab() {
        use std::error::Error;
        use self::error::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }

    pub mod anothererrormod {
        generate_error_imports!();
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    }

    #[test]
    fn test_other_a() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_other_b() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_other_ab() {
        use std::error::Error;
        use self::anothererrormod::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }
}
<commit_msg>Import IntoError trait<commit_after>use into::IntoError;

#[macro_export]
macro_rules! generate_error_imports {
    () => {
        use std::error::Error;
        use std::fmt::Error as FmtError;
        use std::fmt::{Display, Formatter};

        use $crate::into::IntoError;
    }
}

#[macro_export]
macro_rules! generate_error_module {
    ( $exprs:item ) => {
        pub mod error {
            generate_error_imports!();
            $exprs
        }
    }
}

#[macro_export]
macro_rules! generate_error_types {
    (
        $name: ident,
        $kindname: ident,
        $($kind:ident => $string:expr),*
    ) => {
        #[derive(Clone, Copy, Debug, PartialEq)]
        pub enum $kindname {
            $( $kind ),*
        }

        impl Display for $kindname {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                let s = match *self {
                    $( $kindname::$kind => $string ),*
                };
                try!(write!(fmt, "{}", s));
                Ok(())
            }

        }

        impl IntoError for $kindname {
            type Target = $name;

            fn into_error(self) -> Self::Target {
                $name::new(self, None)
            }

            fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target {
                $name::new(self, Some(cause))
            }

        }

        #[derive(Debug)]
        pub struct $name {
            err_type: $kindname,
            cause: Option<Box<Error>>,
        }

        impl $name {

            pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name {
                $name {
                    err_type: errtype,
                    cause: cause,
                }
            }

            pub fn err_type(&self) -> $kindname {
                self.err_type
            }

        }

        impl Display for $name {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                try!(write!(fmt, "[{}]", self.err_type));
                Ok(())
            }

        }

        impl Error for $name {

            fn description(&self) -> &str {
                match self.err_type {
                    $( $kindname::$kind => $string ),*
                }
            }

            fn cause(&self) -> Option<&Error> {
                self.cause.as_ref().map(|e| &**e)
            }

        }

    }
}

#[cfg(test)]
mod test {

    generate_error_module!(
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    );

    #[test]
    fn test_a() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_b() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_ab() {
        use std::error::Error;
        use self::error::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }

    pub mod anothererrormod {
        generate_error_imports!();
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    }

    #[test]
    fn test_other_a() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_other_b() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_other_ab() {
        use std::error::Error;
        use self::anothererrormod::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }
}
<|endoftext|>


<commit_before>use std::time::Instant;
use std::sync::mpsc::Receiver;
use std::collections::HashMap;

use super::{Event, Action};
use super::pool::Pool;
use super::try_iter::try_iter;

fn pool_action(pool: &mut Pool, ts: Instant, action: Action) {
    use super::Action::*;
    match action {
        // handled earlier
        NewSessionPool {..} => unreachable!(),
        StopSessionPool => unreachable!(),
        // Connection management
        NewConnection { conn_id, channel } => {
            pool.add_connection(conn_id, channel);
        }
        Associate { session_id, conn_id, metadata } => {
            pool.associate(conn_id, session_id, ts, metadata);
        }
        UpdateActivity { conn_id, timestamp } => {
            pool.update_activity(conn_id, timestamp);
        }
        Disconnect { conn_id } => {
            pool.del_connection(conn_id);
        }
        // Subscriptions
        Subscribe { conn_id, topic } => {
            pool.subscribe(conn_id, topic);
        }
        Unsubscribe { conn_id, topic } => {
            pool.unsubscribe(conn_id, topic);
        }
        Publish { topic, data } => {
            pool.publish(topic, data);
        }
        // Lattices
        Attach { conn_id, namespace } => {
            pool.lattice_attach(conn_id, namespace);
        }
        Lattice { namespace, delta } => {
            pool.lattice_update(namespace, delta);
        }
        Detach { conn_id, namespace } => {
            pool.lattice_detach(conn_id, namespace);
        }
    }
}

pub fn run(rx: Receiver<Event>) {
    use super::Action::*;
    use std::sync::mpsc::RecvTimeoutError::*;

    let mut pools = HashMap::new();

    loop {
        let timeout = pools.iter_mut()
            .map(|(_, pool): (_, &mut Pool)| pool.cleanup(Instant::now()))
            .flat_map(|x| x)
            .min();
        let result = match timeout {
            Some(t) => rx.recv_timeout(t.duration_since(Instant::now())),
            None => rx.recv().map_err(|_| Disconnected),
        };
        let value = match result {
            Ok(x) => Some(x),
            Err(Timeout) => continue,
            Err(Disconnected) => {
                panic!("Process pools are not needed for anyone");
            }
        };
        for msg in value.into_iter().chain(try_iter(&rx)) {
            let Event { timestamp, action, pool } = msg;
            match action {
                // Pool management
                NewSessionPool { config, channel } => {
                    pools.insert(pool.clone(),
                        Pool::new(pool, config, channel));
                }
                StopSessionPool => {
                    unimplemented!();
                }
                _ => {
                    // For all other actions we resolve pool first
                    pools.get_mut(&pool)
                    .map(|p| pool_action(p, timestamp, action))
                    .unwrap_or_else(|| debug!("Undefined pool {:?}", pool))
                }
            }
        }
    }
}
<commit_msg>fix chat processor main loop (timestamp)<commit_after>use std::time::Instant;
use std::sync::mpsc::Receiver;
use std::collections::HashMap;

use super::{Event, Action};
use super::pool::Pool;
use super::try_iter::try_iter;

fn pool_action(pool: &mut Pool, ts: Instant, action: Action) {
    use super::Action::*;
    match action {
        // handled earlier
        NewSessionPool {..} => unreachable!(),
        StopSessionPool => unreachable!(),
        // Connection management
        NewConnection { conn_id, channel } => {
            pool.add_connection(conn_id, channel);
        }
        Associate { session_id, conn_id, metadata } => {
            pool.associate(conn_id, session_id, ts, metadata);
        }
        UpdateActivity { conn_id, timestamp } => {
            pool.update_activity(conn_id, timestamp);
        }
        Disconnect { conn_id } => {
            pool.del_connection(conn_id);
        }
        // Subscriptions
        Subscribe { conn_id, topic } => {
            pool.subscribe(conn_id, topic);
        }
        Unsubscribe { conn_id, topic } => {
            pool.unsubscribe(conn_id, topic);
        }
        Publish { topic, data } => {
            pool.publish(topic, data);
        }
        // Lattices
        Attach { conn_id, namespace } => {
            pool.lattice_attach(conn_id, namespace);
        }
        Lattice { namespace, delta } => {
            pool.lattice_update(namespace, delta);
        }
        Detach { conn_id, namespace } => {
            pool.lattice_detach(conn_id, namespace);
        }
    }
}

pub fn run(rx: Receiver<Event>) {
    use super::Action::*;
    use std::sync::mpsc::RecvTimeoutError::*;

    let mut pools = HashMap::new();

    loop {
        let now = Instant::now();
        let timeout = pools.iter_mut()
            .map(|(_, pool): (_, &mut Pool)| pool.cleanup(now))
            .flat_map(|x| x)
            .min();
        let result = match timeout {
            Some(t) => rx.recv_timeout(t.duration_since(now)),
            None => rx.recv().map_err(|_| Disconnected),
        };
        let value = match result {
            Ok(x) => Some(x),
            Err(Timeout) => continue,
            Err(Disconnected) => {
                panic!("Process pools are not needed for anyone");
            }
        };
        for msg in value.into_iter().chain(try_iter(&rx)) {
            let Event { timestamp, action, pool } = msg;
            match action {
                // Pool management
                NewSessionPool { config, channel } => {
                    pools.insert(pool.clone(),
                        Pool::new(pool, config, channel));
                }
                StopSessionPool => {
                    unimplemented!();
                }
                _ => {
                    // For all other actions we resolve pool first
                    pools.get_mut(&pool)
                    .map(|p| pool_action(p, timestamp, action))
                    .unwrap_or_else(|| debug!("Undefined pool {:?}", pool))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod messages;

use address::Address;
use mio;
use network;
use self::messages::{Message, TextMessage, MessageAcknowledgement, Envelope};
use std::collections::{HashMap, HashSet};
use std::sync::mpsc;
use std::thread;

#[derive(Debug)]
pub enum Task {
    HandleNetworkEvent(network::Event),
    ScheduleMessageDelivery(Address, TextMessage)
}

#[derive(Debug)]
pub enum ScheduledTask {
    DeliverMessage(Address, TextMessage),
}

#[derive(Clone, Debug)]
pub enum Event {
    ReceivedTextMessage {
        id: Address,
        sender: Address,
        text: String
    },

    ReceivedMessageAcknowledgement {
        message_id: Address,
    }
}

pub struct Client {
    address: Address,
    network_commands: Option<network::TaskSender>,
    received: HashSet<Address>,
    pending_deliveries: HashMap<Address, mio::Timeout>,
    delivered: HashMap<Address, usize>,
    acknowledgements: HashMap<Address, MessageAcknowledgement>,
    event_listeners: Vec<mpsc::Sender<Event>>
}

impl Client {
    pub fn new(address: Address) -> Client {
        Client {
            address: address,
            network_commands: None,
            received: HashSet::new(),
            pending_deliveries: HashMap::new(),
            delivered: HashMap::new(),
            acknowledgements: HashMap::new(),
            event_listeners: Vec::new()
        }
    }

    pub fn run(mut self, mut network: network::Network) -> mio::Sender<Task> {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let (event_sender, event_receiver) = mpsc::channel();
        network.register_event_listener(event_sender);
        let notify_channel = event_loop.channel();

        thread::spawn(move|| {
            for event in event_receiver.iter() {
                notify_channel
                    .send(Task::HandleNetworkEvent(event))
                    .unwrap_or_else(|err| info!("Couldn't handle network event: {:?}", err));
            }
        });

        self.network_commands = Some(network.run());

        let notify_channel = event_loop.channel();
        info!("Running client at {}", self.address);
        thread::spawn(move || event_loop.run(&mut self).unwrap());
        notify_channel
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_networking_event(&mut self, event: network::Event, event_loop: &mut mio::EventLoop<Client>) {
        match event {
            network::Event::ReceivedPacket(sender, data) => {
                let envelope = messages::decode(data);
                let Envelope { recipient, .. } = envelope;

                match envelope.message {
                    Message::TextMessage(text_message) => {
                        if recipient == self.address {
                            if self.received.insert(text_message.id) {
                                let event = Event::ReceivedTextMessage {
                                    id: text_message.id,
                                    sender: text_message.sender,
                                    text: text_message.text
                                };
                                self.broadcast_event(event);
                                let ack = MessageAcknowledgement::new(text_message.id);
                                self.deliver_acknowledgement(text_message.sender, ack, event_loop);
                            }
                        } else {
                            if let Some(ack) = self.acknowledgements.remove(&text_message.id) {
                                self.deliver_acknowledgement(sender, ack.clone(), event_loop);
                                self.acknowledgements.insert(text_message.id, ack);
                            } else {
                                self.schedule_message_delivery(recipient, text_message, event_loop);
                            }
                        }
                    }
                    Message::MessageAcknowledgement(ack) => {
                        debug!("ack {}", ack.message_id);
                        self.pending_deliveries.remove(&ack.message_id).map(|p| event_loop.clear_timeout(p));

                        if let None = self.acknowledgements.insert(ack.message_id, ack.clone()) {
                            if recipient == self.address {
                                self.broadcast_event(Event::ReceivedMessageAcknowledgement {
                                    message_id: ack.message_id
                                });
                                println!("Message acked: {}", ack.message_id);
                            } else {
                                self.deliver_acknowledgement(recipient, ack, event_loop);
                            }
                        }
                    }
                }
            }
        }
    }

    fn schedule_message_delivery(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let message_id = text_message.id;
        if !self.pending_deliveries.contains_key(&message_id) {
            let delivered = self.delivered.entry(message_id).or_insert(0);
            let delay = (2u64.pow(*delivered as u32) - 1) * 1000;
            debug!("Deliver {} with delay {:?}", message_id, delay);
            let timeout = event_loop.timeout_ms(ScheduledTask::DeliverMessage(recipient, text_message), delay).unwrap();
            self.pending_deliveries.insert(message_id, timeout);
            *delivered += 1;
        }
    }

    fn deliver_acknowledgement(&mut self, recipient: Address, acknowledgement: MessageAcknowledgement, _event_loop: &mut mio::EventLoop<Client>) {
        if let Some(ref commands) = self.network_commands {
            let envelope = acknowledgement.envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode())).unwrap();
        }
    }

    fn deliver_message(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let delivered = self.network_commands.as_ref().map(|commands| {
            let envelope = text_message.clone().envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode()))
        }).unwrap();

        if let Ok(_) = delivered {
            self.pending_deliveries.remove(&text_message.id);
            self.schedule_message_delivery(recipient, text_message, event_loop);
        }
    }

    fn broadcast_event(&self, event: Event) {
        for listener in self.event_listeners.iter() {
            listener.send(event.clone()).expect("Could not broadcast event");
        }
    }
}

impl mio::Handler for Client {
    type Timeout = ScheduledTask;
    type Message = Task;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Client>, task: Task) {
        match task {
            Task::HandleNetworkEvent(event) => self.handle_networking_event(event, event_loop),
            Task::ScheduleMessageDelivery(recipient, message) => self.schedule_message_delivery(recipient, message, event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Client>, task: ScheduledTask) {
        match task {
            ScheduledTask::DeliverMessage(recipient, message) => self.deliver_message(recipient, message, event_loop)
        }
    }
}
<commit_msg>Include client messages in event enums rather than copying fields<commit_after>pub mod messages;

use address::Address;
use mio;
use network;
use self::messages::{Message, TextMessage, MessageAcknowledgement, Envelope};
use std::collections::{HashMap, HashSet};
use std::sync::mpsc;
use std::thread;

#[derive(Debug)]
pub enum Task {
    HandleNetworkEvent(network::Event),
    ScheduleMessageDelivery(Address, TextMessage)
}

#[derive(Debug)]
pub enum ScheduledTask {
    DeliverMessage(Address, TextMessage),
}

#[derive(Clone, Debug)]
pub enum Event {
    ReceivedTextMessage(TextMessage),
    ReceivedMessageAcknowledgement(MessageAcknowledgement)
}

pub struct Client {
    address: Address,
    network_commands: Option<network::TaskSender>,
    received: HashSet<Address>,
    pending_deliveries: HashMap<Address, mio::Timeout>,
    delivered: HashMap<Address, usize>,
    acknowledgements: HashMap<Address, MessageAcknowledgement>,
    event_listeners: Vec<mpsc::Sender<Event>>
}

impl Client {
    pub fn new(address: Address) -> Client {
        Client {
            address: address,
            network_commands: None,
            received: HashSet::new(),
            pending_deliveries: HashMap::new(),
            delivered: HashMap::new(),
            acknowledgements: HashMap::new(),
            event_listeners: Vec::new()
        }
    }

    pub fn run(mut self, mut network: network::Network) -> mio::Sender<Task> {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let (event_sender, event_receiver) = mpsc::channel();
        network.register_event_listener(event_sender);
        let notify_channel = event_loop.channel();

        thread::spawn(move|| {
            for event in event_receiver.iter() {
                notify_channel
                    .send(Task::HandleNetworkEvent(event))
                    .unwrap_or_else(|err| info!("Couldn't handle network event: {:?}", err));
            }
        });

        self.network_commands = Some(network.run());

        let notify_channel = event_loop.channel();
        info!("Running client at {}", self.address);
        thread::spawn(move || event_loop.run(&mut self).unwrap());
        notify_channel
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_networking_event(&mut self, event: network::Event, event_loop: &mut mio::EventLoop<Client>) {
        match event {
            network::Event::ReceivedPacket(sender, data) => {
                let envelope = messages::decode(data);
                let Envelope { recipient, .. } = envelope;

                match envelope.message {
                    Message::TextMessage(text_message) => {
                        if recipient == self.address {
                            if self.received.insert(text_message.id) {
                                let ack = MessageAcknowledgement::new(text_message.id);
                                let sender = text_message.sender;
                                let event = Event::ReceivedTextMessage(text_message);
                                self.broadcast_event(event);
                                self.deliver_acknowledgement(sender, ack, event_loop);
                            }
                        } else {
                            if let Some(ack) = self.acknowledgements.remove(&text_message.id) {
                                self.deliver_acknowledgement(sender, ack.clone(), event_loop);
                                self.acknowledgements.insert(text_message.id, ack);
                            } else {
                                self.schedule_message_delivery(recipient, text_message, event_loop);
                            }
                        }
                    }
                    Message::MessageAcknowledgement(ack) => {
                        debug!("ack {}", ack.message_id);
                        self.pending_deliveries.remove(&ack.message_id).map(|p| event_loop.clear_timeout(p));

                        if let None = self.acknowledgements.insert(ack.message_id, ack.clone()) {
                            if recipient == self.address {
                                self.broadcast_event(Event::ReceivedMessageAcknowledgement(ack));
                            } else {
                                self.deliver_acknowledgement(recipient, ack, event_loop);
                            }
                        }
                    }
                }
            }
        }
    }

    fn schedule_message_delivery(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let message_id = text_message.id;
        if !self.pending_deliveries.contains_key(&message_id) {
            let delivered = self.delivered.entry(message_id).or_insert(0);
            let delay = (2u64.pow(*delivered as u32) - 1) * 1000;
            debug!("Deliver {} with delay {:?}", message_id, delay);
            let timeout = event_loop.timeout_ms(ScheduledTask::DeliverMessage(recipient, text_message), delay).unwrap();
            self.pending_deliveries.insert(message_id, timeout);
            *delivered += 1;
        }
    }

    fn deliver_acknowledgement(&mut self, recipient: Address, acknowledgement: MessageAcknowledgement, _event_loop: &mut mio::EventLoop<Client>) {
        if let Some(ref commands) = self.network_commands {
            let envelope = acknowledgement.envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode())).unwrap();
        }
    }

    fn deliver_message(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let delivered = self.network_commands.as_ref().map(|commands| {
            let envelope = text_message.clone().envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode()))
        }).unwrap();

        if let Ok(_) = delivered {
            self.pending_deliveries.remove(&text_message.id);
            self.schedule_message_delivery(recipient, text_message, event_loop);
        }
    }

    fn broadcast_event(&self, event: Event) {
        for listener in self.event_listeners.iter() {
            listener.send(event.clone()).expect("Could not broadcast event");
        }
    }
}

impl mio::Handler for Client {
    type Timeout = ScheduledTask;
    type Message = Task;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Client>, task: Task) {
        match task {
            Task::HandleNetworkEvent(event) => self.handle_networking_event(event, event_loop),
            Task::ScheduleMessageDelivery(recipient, message) => self.schedule_message_delivery(recipient, message, event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Client>, task: ScheduledTask) {
        match task {
            ScheduledTask::DeliverMessage(recipient, message) => self.deliver_message(recipient, message, event_loop)
        }
    }
}
<|endoftext|>