<commit_before>use std::{
    hash::Hash,
    iter::{from_fn, FromIterator},
};

use indexmap::IndexSet;

use crate::{
    visit::{IntoNeighborsDirected, NodeCount},
    Direction::Outgoing,
};

/// Returns an iterator that produces all simple paths from `from` node to `to`, which contains at least `min_intermediate_nodes` nodes
/// and at most `max_intermediate_nodes`, if given, or limited by the graph's order otherwise. The simple path is a path without repetitions.
///
/// This algorithm is adapted from https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html
///
/// # Example
/// ```
/// use petgraph::{algo, prelude::*};
///
/// let mut graph = DiGraph::<&str, i32>::new();
///
/// let a = graph.add_node("a");
/// let b = graph.add_node("b");
/// let c = graph.add_node("c");
/// let d = graph.add_node("d");
///
/// graph.extend_with_edges(&[(a, b, 1), (b, c, 1), (c, d, 1), (a, b, 1), (b, d, 1)]);
///
/// let ways = algo::all_simple_paths::<Vec<_>, _>(&graph, a, d, 0, None)
///   .collect::<Vec<_>>();
///
/// assert_eq!(4, ways.len());
/// ```
pub fn all_simple_paths<TargetColl, G>(
    graph: G,
    from: G::NodeId,
    to: G::NodeId,
    min_intermediate_nodes: usize,
    max_intermediate_nodes: Option<usize>,
) -> impl Iterator<Item = TargetColl>
where
    G: NodeCount,
    G: IntoNeighborsDirected,
    G::NodeId: Eq + Hash,
    TargetColl: FromIterator<G::NodeId>,
{
    // how many nodes are allowed in simple path up to target node
    // it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
    // than constantly add 1 to length of current path
    let max_length = if let Some(l) = max_intermediate_nodes {
        l + 1
    } else {
        graph.node_count() - 1
    };

    let min_length = min_intermediate_nodes + 1;

    // list of visited nodes
    let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
    // list of childs of currently exploring path nodes,
    // last elem is list of childs of last visited node
    let mut stack = vec![graph.neighbors_directed(from, Outgoing)];

    from_fn(move || {
        while let Some(children) = stack.last_mut() {
            if let Some(child) = children.next() {
                if visited.len() < max_length {
                    if child == to {
                        if visited.len() >= min_length {
                            let path = visited
                                .iter()
                                .cloned()
                                .chain(Some(to))
                                .collect::<TargetColl>();
                            return Some(path);
                        }
                    } else if !visited.contains(&child) {
                        visited.insert(child);
                        stack.push(graph.neighbors_directed(child, Outgoing));
                    }
                } else {
                    if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
                        let path = visited
                            .iter()
                            .cloned()
                            .chain(Some(to))
                            .collect::<TargetColl>();
                        return Some(path);
                    }
                    stack.pop();
                    visited.pop();
                }
            } else {
                stack.pop();
                visited.pop();
            }
        }
        None
    })
}

#[cfg(test)]
mod test {
    use std::{collections::HashSet, iter::FromIterator};

    use itertools::assert_equal;

    use crate::{dot::Dot, prelude::DiGraph};

    use super::all_simple_paths;

    #[test]
    fn test_all_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (0, 2),
            (0, 3),
            (1, 2),
            (1, 3),
            (2, 3),
            (2, 4),
            (3, 2),
            (3, 4),
            (4, 2),
            (4, 5),
            (5, 2),
            (5, 3),
        ]);

        let expexted_simple_paths_0_to_5 = vec![
            vec![0usize, 1, 2, 3, 4, 5],
            vec![0, 1, 2, 4, 5],
            vec![0, 1, 3, 2, 4, 5],
            vec![0, 1, 3, 4, 5],
            vec![0, 2, 3, 4, 5],
            vec![0, 2, 4, 5],
            vec![0, 3, 2, 4, 5],
            vec![0, 3, 4, 5],
        ];

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_5: HashSet<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();
        assert_eq!(actual_simple_paths_0_to_5.len(), 8);
        assert_eq!(
            HashSet::from_iter(expexted_simple_paths_0_to_5),
            actual_simple_paths_0_to_5
        );
    }

    #[test]
    fn test_one_simple_path() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);

        let expexted_simple_paths_0_to_1 = &[vec![0usize, 1]];
        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_1: Vec<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();

        assert_eq!(actual_simple_paths_0_to_1.len(), 1);
        assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
    }

    #[test]
    fn test_no_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_2: Vec<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();

        assert_eq!(actual_simple_paths_0_to_2.len(), 0);
    }
}
<commit_msg>Fix bare url in doc (#450)<commit_after>use std::{
    hash::Hash,
    iter::{from_fn, FromIterator},
};

use indexmap::IndexSet;

use crate::{
    visit::{IntoNeighborsDirected, NodeCount},
    Direction::Outgoing,
};

/// Returns an iterator that produces all simple paths from `from` node to `to`, which contains at least `min_intermediate_nodes` nodes
/// and at most `max_intermediate_nodes`, if given, or limited by the graph's order otherwise. The simple path is a path without repetitions.
///
/// This algorithm is adapted from <https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html>.
///
/// # Example
/// ```
/// use petgraph::{algo, prelude::*};
///
/// let mut graph = DiGraph::<&str, i32>::new();
///
/// let a = graph.add_node("a");
/// let b = graph.add_node("b");
/// let c = graph.add_node("c");
/// let d = graph.add_node("d");
///
/// graph.extend_with_edges(&[(a, b, 1), (b, c, 1), (c, d, 1), (a, b, 1), (b, d, 1)]);
///
/// let ways = algo::all_simple_paths::<Vec<_>, _>(&graph, a, d, 0, None)
///   .collect::<Vec<_>>();
///
/// assert_eq!(4, ways.len());
/// ```
pub fn all_simple_paths<TargetColl, G>(
    graph: G,
    from: G::NodeId,
    to: G::NodeId,
    min_intermediate_nodes: usize,
    max_intermediate_nodes: Option<usize>,
) -> impl Iterator<Item = TargetColl>
where
    G: NodeCount,
    G: IntoNeighborsDirected,
    G::NodeId: Eq + Hash,
    TargetColl: FromIterator<G::NodeId>,
{
    // how many nodes are allowed in simple path up to target node
    // it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
    // than constantly add 1 to length of current path
    let max_length = if let Some(l) = max_intermediate_nodes {
        l + 1
    } else {
        graph.node_count() - 1
    };

    let min_length = min_intermediate_nodes + 1;

    // list of visited nodes
    let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
    // list of childs of currently exploring path nodes,
    // last elem is list of childs of last visited node
    let mut stack = vec![graph.neighbors_directed(from, Outgoing)];

    from_fn(move || {
        while let Some(children) = stack.last_mut() {
            if let Some(child) = children.next() {
                if visited.len() < max_length {
                    if child == to {
                        if visited.len() >= min_length {
                            let path = visited
                                .iter()
                                .cloned()
                                .chain(Some(to))
                                .collect::<TargetColl>();
                            return Some(path);
                        }
                    } else if !visited.contains(&child) {
                        visited.insert(child);
                        stack.push(graph.neighbors_directed(child, Outgoing));
                    }
                } else {
                    if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
                        let path = visited
                            .iter()
                            .cloned()
                            .chain(Some(to))
                            .collect::<TargetColl>();
                        return Some(path);
                    }
                    stack.pop();
                    visited.pop();
                }
            } else {
                stack.pop();
                visited.pop();
            }
        }
        None
    })
}

#[cfg(test)]
mod test {
    use std::{collections::HashSet, iter::FromIterator};

    use itertools::assert_equal;

    use crate::{dot::Dot, prelude::DiGraph};

    use super::all_simple_paths;

    #[test]
    fn test_all_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (0, 2),
            (0, 3),
            (1, 2),
            (1, 3),
            (2, 3),
            (2, 4),
            (3, 2),
            (3, 4),
            (4, 2),
            (4, 5),
            (5, 2),
            (5, 3),
        ]);

        let expexted_simple_paths_0_to_5 = vec![
            vec![0usize, 1, 2, 3, 4, 5],
            vec![0, 1, 2, 4, 5],
            vec![0, 1, 3, 2, 4, 5],
            vec![0, 1, 3, 4, 5],
            vec![0, 2, 3, 4, 5],
            vec![0, 2, 4, 5],
            vec![0, 3, 2, 4, 5],
            vec![0, 3, 4, 5],
        ];

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_5: HashSet<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();
        assert_eq!(actual_simple_paths_0_to_5.len(), 8);
        assert_eq!(
            HashSet::from_iter(expexted_simple_paths_0_to_5),
            actual_simple_paths_0_to_5
        );
    }

    #[test]
    fn test_one_simple_path() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);

        let expexted_simple_paths_0_to_1 = &[vec![0usize, 1]];
        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_1: Vec<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();

        assert_eq!(actual_simple_paths_0_to_1.len(), 1);
        assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
    }

    #[test]
    fn test_no_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_2: Vec<Vec<_>> =
            all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
                .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
                .collect();

        assert_eq!(actual_simple_paths_0_to_2.len(), 0);
    }
}
<|endoftext|>


<commit_before>use ir::{self,types,value,Type};
use std::fmt;
use util;
use super::Value;
use num::bigint::ToBigInt;
use bit_vec::BitVec;

pub trait ExpressionTrait : Clone + fmt::Debug + Into<Expression>
{
}

#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Expression
{
    Literal(value::Literal),
    Register(value::Register),
    Instruction(ir::Instruction),

    GlobalRef(value::GlobalRef),
    BlockRef(value::BlockRef),
    FunctionRef(value::FunctionRef),
    RegisterRef(value::RegisterRef),
}

impl Expression
{
    pub fn decimal(_ty: types::Decimal, _bits: BitVec) -> Self {
        unimplemented!();
    }

    pub fn strukt(_fields: Vec<Value>) -> Self {
        unimplemented!();
    }

    pub fn unit_struct() -> Self {
        unimplemented!();
    }

    /// Creates an integer, returning `None` if `val` cannot fit into `ty`.
    pub fn integer<T: ToBigInt>(ty: types::Integer, val: T) -> Option<Self> {
        ir::value::Literal::integer(ty,val).map(|i| i.into())
    }

    /// Creates a signed integer value.
    pub fn i<T: ToBigInt>(bit_width: u16, value: T) -> Self {
        let ty = types::Integer::new(util::IntegerKind::Signed, bit_width);
        Self::integer(ty, value).unwrap()
    }

    /// Creates an unsigned integer value.
    pub fn u<T: ToBigInt>(bit_width: u16, value: T) -> Self {
       let ty = types::Integer::new(util::IntegerKind::Unsigned, bit_width);
       Self::integer(ty, value).unwrap()
    }

    pub fn u8(value: u8)   -> Self { Self::u(8, value) }
    pub fn u16(value: u16) -> Self { Self::u(16, value) }
    pub fn u32(value: u32) -> Self { Self::u(32, value) }
    pub fn u64(value: u64) -> Self { Self::u(64, value) }
    pub fn i8(value: i8)   -> Self { Self::i(8, value) }
    pub fn i16(value: i16) -> Self { Self::i(16, value) }
    pub fn i32(value: i32) -> Self { Self::i(32, value) }
    pub fn i64(value: i64) -> Self { Self::i(64, value) }

    pub fn global_ref(global: &ir::Global) -> Expression {
        value::GlobalRef::reference(global).into()
    }

    pub fn block_ref(block: &ir::Block) -> Expression {
        value::BlockRef::reference(block).into()
    }

    pub fn function_ref(func: &ir::Function) -> Expression {
        value::FunctionRef::reference(func).into()
    }

    pub fn register_ref(reg: &ir::value::Register) -> Expression {
        value::RegisterRef::reference(reg).into()
    }

    /// Creates an unnamed register.
    pub fn register<V>(value: V) -> Expression
        where V: Into<Value> {
        value::Register::unnamed(value.into()).into()
    }

    /// Creates a named register.
    pub fn register_named<I>(name: I, value: Expression) -> Expression
        where I: Into<String> {

        let name = ir::Name::named(name);
        value::Register::new(name, value.into()).into()
    }

    pub fn instruction<I>(inst: I) -> Self
        where I: Into<ir::Instruction> {
        Expression::Instruction(inst.into())
    }

    pub fn add<V>(lhs: V, rhs: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::add(lhs, rhs)
        )
    }

    pub fn sub<V>(lhs: V, rhs: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::sub(lhs, rhs)
        )
    }

    pub fn mul<V>(lhs: V, rhs: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::mul(lhs, rhs)
        )
    }

    pub fn div<V>(lhs: V, rhs: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::div(lhs, rhs)
        )
    }

    pub fn shl<V>(value: V, amount: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::shl(value, amount)
        )
    }

    pub fn shr<V>(value: V, amount: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::shr(value, amount)
        )
    }

    pub fn call<V>(target: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::call(target)
        )
    }

    pub fn br<V>(target: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::br(target)
        )
    }

    pub fn ret(value: ir::Value) -> Self {
        Expression::instruction(
            ir::Instruction::ret(value)
        )
    }

    pub fn ret_void() -> Self {
        Expression::instruction(
            ir::Instruction::ret_void()
        )
    }

    pub fn as_literal(&self) -> Option<&value::Literal> {
        match *self {
            Expression::Literal(ref v) => Some(v),
            _ => None,
        }
    }

    pub fn is_literal(&self) -> bool {
        match *self {
            Expression::Literal(..) => true,
            _ => false,
        }
    }

    /// Checks if the value is an instruction.
    pub fn is_instruction(&self) -> bool {
        match *self {
            Expression::Instruction(..) => true,
            _ => false,
        }
    }

    pub fn is_function_ref(&self) -> bool {
        match *self {
            Expression::FunctionRef(..) => true,
            _ => false,
        }
    }

    pub fn is_block_ref(&self) -> bool {
        match *self {
            Expression::BlockRef(..) => true,
            _ => false,
        }
    }

    pub fn ty(&self) -> ir::Type {
         match *self {
            Expression::Literal(ref val) => val.ty(),
            Expression::Register(ref val) => val.ty(),
            Expression::Instruction(ref val) => val.ty(),
            Expression::GlobalRef(ref val) => val.ty(),
            Expression::BlockRef(ref val) => val.ty(),
            Expression::FunctionRef(ref val) => val.ty(),
            Expression::RegisterRef(ref val) => val.ty(),
        }
    }

    pub fn is_simple(&self) -> bool {
         match *self{
             Expression::Literal(..) => true,
             Expression::Register(..) => true,
             Expression::Instruction(..) => false,
             Expression::GlobalRef(..) => true,
             Expression::BlockRef(..) => true,
             Expression::FunctionRef(..) => true,
             Expression::RegisterRef(..) => true,
         }
    }

    pub fn subvalues(&self) -> Vec<&Value> {
        match *self {
            Expression::Instruction(ref i) => i.subvalues(),
            _ => Vec::new(),
        }
    }

    pub fn map_subvalues<F>(self, _f: F) -> Self
        where F: FnMut(Value) -> Value {
        unimplemented!();
    }

    pub fn flatten(self, block: &mut ir::Block) -> Self {
        // only instructions need flattening
        if let Expression::Instruction(i) = self {
            i.flatten(block).into()
        } else {
            self
        }
    }

    pub fn is_single_critical(&self) -> bool {
        match *self {
            Expression::Literal(..) => false,
            Expression::Instruction(ref i) => i.is_single_critical(),
            _ => true,
        }
    }

    pub fn is_terminator(&self) -> bool {
        // only instructions can be terminators
        if let ir::Expression::Instruction(ref inst) = *self {
            inst.is_terminator()
        } else {
            false
        }
    }
}

impl ExpressionTrait for Expression { }

/// Implements Into<Expression> for u8,i32,etc
macro_rules! impl_into_value_for_integers {
    (
        $( $ty:ident ),*
    ) => {
        $(
            impl Into<Expression> for $ty
            {
                fn into(self) -> Expression {
                    Expression::$ty(self)
                }
            }

            impl Into<Value> for $ty
            {
                fn into(self) -> Value {
                    Value::new(self.into())
                }
            }
        )*
    }
}

impl_into_value_for_integers!(u8,u16,u32,u64,i8,i16,i32,i64);
<commit_msg>Implemented Expression.map_subvalues<commit_after>use ir::{self,types,value,Type};
use std::fmt;
use util;
use super::Value;
use num::bigint::ToBigInt;
use bit_vec::BitVec;

pub trait ExpressionTrait : Clone + fmt::Debug + Into<Expression>
{
}

#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Expression
{
    Literal(value::Literal),
    Register(value::Register),
    Instruction(ir::Instruction),

    GlobalRef(value::GlobalRef),
    BlockRef(value::BlockRef),
    FunctionRef(value::FunctionRef),
    RegisterRef(value::RegisterRef),
}

impl Expression
{
    pub fn decimal(_ty: types::Decimal, _bits: BitVec) -> Self {
        unimplemented!();
    }

    pub fn strukt(_fields: Vec<Value>) -> Self {
        unimplemented!();
    }

    pub fn unit_struct() -> Self {
        unimplemented!();
    }

    /// Creates an integer, returning `None` if `val` cannot fit into `ty`.
    pub fn integer<T: ToBigInt>(ty: types::Integer, val: T) -> Option<Self> {
        ir::value::Literal::integer(ty,val).map(|i| i.into())
    }

    /// Creates a signed integer value.
    pub fn i<T: ToBigInt>(bit_width: u16, value: T) -> Self {
        let ty = types::Integer::new(util::IntegerKind::Signed, bit_width);
        Self::integer(ty, value).unwrap()
    }

    /// Creates an unsigned integer value.
    pub fn u<T: ToBigInt>(bit_width: u16, value: T) -> Self {
       let ty = types::Integer::new(util::IntegerKind::Unsigned, bit_width);
       Self::integer(ty, value).unwrap()
    }

    pub fn u8(value: u8)   -> Self { Self::u(8, value) }
    pub fn u16(value: u16) -> Self { Self::u(16, value) }
    pub fn u32(value: u32) -> Self { Self::u(32, value) }
    pub fn u64(value: u64) -> Self { Self::u(64, value) }
    pub fn i8(value: i8)   -> Self { Self::i(8, value) }
    pub fn i16(value: i16) -> Self { Self::i(16, value) }
    pub fn i32(value: i32) -> Self { Self::i(32, value) }
    pub fn i64(value: i64) -> Self { Self::i(64, value) }

    pub fn global_ref(global: &ir::Global) -> Expression {
        value::GlobalRef::reference(global).into()
    }

    pub fn block_ref(block: &ir::Block) -> Expression {
        value::BlockRef::reference(block).into()
    }

    pub fn function_ref(func: &ir::Function) -> Expression {
        value::FunctionRef::reference(func).into()
    }

    pub fn register_ref(reg: &ir::value::Register) -> Expression {
        value::RegisterRef::reference(reg).into()
    }

    /// Creates an unnamed register.
    pub fn register<V>(value: V) -> Expression
        where V: Into<Value> {
        value::Register::unnamed(value.into()).into()
    }

    /// Creates a named register.
    pub fn register_named<I>(name: I, value: Expression) -> Expression
        where I: Into<String> {

        let name = ir::Name::named(name);
        value::Register::new(name, value.into()).into()
    }

    pub fn instruction<I>(inst: I) -> Self
        where I: Into<ir::Instruction> {
        Expression::Instruction(inst.into())
    }

    pub fn add<V>(lhs: V, rhs: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::add(lhs, rhs)
        )
    }

    pub fn sub<V>(lhs: V, rhs: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::sub(lhs, rhs)
        )
    }

    pub fn mul<V>(lhs: V, rhs: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::mul(lhs, rhs)
        )
    }

    pub fn div<V>(lhs: V, rhs: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::div(lhs, rhs)
        )
    }

    pub fn shl<V>(value: V, amount: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::shl(value, amount)
        )
    }

    pub fn shr<V>(value: V, amount: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::shr(value, amount)
        )
    }

    pub fn call<V>(target: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::call(target)
        )
    }

    pub fn br<V>(target: V) -> Self
        where V: Into<Value> {
        Expression::instruction(
            ir::Instruction::br(target)
        )
    }

    pub fn ret(value: ir::Value) -> Self {
        Expression::instruction(
            ir::Instruction::ret(value)
        )
    }

    pub fn ret_void() -> Self {
        Expression::instruction(
            ir::Instruction::ret_void()
        )
    }

    pub fn as_literal(&self) -> Option<&value::Literal> {
        match *self {
            Expression::Literal(ref v) => Some(v),
            _ => None,
        }
    }

    pub fn is_literal(&self) -> bool {
        match *self {
            Expression::Literal(..) => true,
            _ => false,
        }
    }

    /// Checks if the value is an instruction.
    pub fn is_instruction(&self) -> bool {
        match *self {
            Expression::Instruction(..) => true,
            _ => false,
        }
    }

    pub fn is_function_ref(&self) -> bool {
        match *self {
            Expression::FunctionRef(..) => true,
            _ => false,
        }
    }

    pub fn is_block_ref(&self) -> bool {
        match *self {
            Expression::BlockRef(..) => true,
            _ => false,
        }
    }

    pub fn ty(&self) -> ir::Type {
         match *self {
            Expression::Literal(ref val) => val.ty(),
            Expression::Register(ref val) => val.ty(),
            Expression::Instruction(ref val) => val.ty(),
            Expression::GlobalRef(ref val) => val.ty(),
            Expression::BlockRef(ref val) => val.ty(),
            Expression::FunctionRef(ref val) => val.ty(),
            Expression::RegisterRef(ref val) => val.ty(),
        }
    }

    pub fn is_simple(&self) -> bool {
         match *self{
             Expression::Literal(..) => true,
             Expression::Register(..) => true,
             Expression::Instruction(..) => false,
             Expression::GlobalRef(..) => true,
             Expression::BlockRef(..) => true,
             Expression::FunctionRef(..) => true,
             Expression::RegisterRef(..) => true,
         }
    }

    pub fn subvalues(&self) -> Vec<&Value> {
        match *self {
            Expression::Instruction(ref i) => i.subvalues(),
            _ => Vec::new(),
        }
    }

    pub fn map_subvalues<F>(self, f: F) -> Self
        where F: FnMut(Value) -> Value {
        match self {
            Expression::Instruction(i) => i.map_subvalues(f).into(),
            _ => self,
        }
    }

    pub fn flatten(self, block: &mut ir::Block) -> Self {
        // only instructions need flattening
        if let Expression::Instruction(i) = self {
            i.flatten(block).into()
        } else {
            self
        }
    }

    pub fn is_single_critical(&self) -> bool {
        match *self {
            Expression::Literal(..) => false,
            Expression::Instruction(ref i) => i.is_single_critical(),
            _ => true,
        }
    }

    pub fn is_terminator(&self) -> bool {
        // only instructions can be terminators
        if let ir::Expression::Instruction(ref inst) = *self {
            inst.is_terminator()
        } else {
            false
        }
    }
}

impl ExpressionTrait for Expression { }

/// Implements Into<Expression> for u8,i32,etc
macro_rules! impl_into_value_for_integers {
    (
        $( $ty:ident ),*
    ) => {
        $(
            impl Into<Expression> for $ty
            {
                fn into(self) -> Expression {
                    Expression::$ty(self)
                }
            }

            impl Into<Value> for $ty
            {
                fn into(self) -> Value {
                    Value::new(self.into())
                }
            }
        )*
    }
}

impl_into_value_for_integers!(u8,u16,u32,u64,i8,i16,i32,i64);
<|endoftext|>


<commit_before>// Copyright 2016 Serde YAML Developers
//
// 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.

//! YAML Serialization
//!
//! This module provides YAML serialization with the type `Serializer`.

use std::{fmt, io, mem};

use yaml_rust::{Yaml, YamlEmitter};
use yaml_rust::yaml;

use serde::ser;

use super::error::{Error, Result};

/// A structure for serializing a Rust value into a YAML value.
pub struct Serializer {
    /// The YAML value to hold the result.
    doc: Yaml,
}

impl Serializer {
    pub fn new() -> Self {
        Serializer {
            doc: Yaml::Null,
        }
    }

    pub fn take(self) -> Yaml {
        self.doc
    }
}

impl ser::Serializer for Serializer {
    type Error = Error;
    type SeqState = ();
    type TupleState = ();
    type TupleStructState = ();
    type TupleVariantState = &'static str;
    type MapState = ();
    type StructState = ();
    type StructVariantState = &'static str;

    fn serialize_bool(&mut self, v: bool) -> Result<()> {
        self.doc = Yaml::Boolean(v);
        Ok(())
    }

    fn serialize_isize(&mut self, v: isize) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i8(&mut self, v: i8) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i16(&mut self, v: i16) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i32(&mut self, v: i32) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i64(&mut self, v: i64) -> Result<()> {
        self.doc = Yaml::Integer(v);
        Ok(())
    }

    fn serialize_usize(&mut self, v: usize) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u8(&mut self, v: u8) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u16(&mut self, v: u16) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u32(&mut self, v: u32) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u64(&mut self, v: u64) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_f32(&mut self, v: f32) -> Result<()> {
        self.doc = Yaml::Real(v.to_string());
        Ok(())
    }

    fn serialize_f64(&mut self, v: f64) -> Result<()> {
        self.doc = Yaml::Real(v.to_string());
        Ok(())
    }

    fn serialize_char(&mut self, value: char) -> Result<()> {
        self.doc = Yaml::String(value.to_string());
        Ok(())
    }

    fn serialize_str(&mut self, value: &str) -> Result<()> {
        self.doc = Yaml::String(String::from(value));
        Ok(())
    }

    fn serialize_bytes(&mut self, value: &[u8]) -> Result<()> {
        let mut state = try!(self.serialize_seq(Some(value.len())));
        for c in value {
            try!(self.serialize_seq_elt(&mut state, c));
        }
        self.serialize_seq_end(state)
    }

    fn serialize_unit(&mut self) -> Result<()> {
        self.doc = Yaml::Null;
        Ok(())
    }

    fn serialize_unit_struct(&mut self, _name: &'static str) -> Result<()> {
        self.doc = Yaml::Null;
        Ok(())
    }

    fn serialize_unit_variant(
        &mut self,
        _name: &str,
        _variant_index: usize,
        variant: &str
    ) -> Result<()> {
        self.doc = Yaml::String(String::from(variant));
        Ok(())
    }

    fn serialize_newtype_struct<T>(
        &mut self,
        _name: &'static str,
        value: T
    ) -> Result<()>
        where T: ser::Serialize,
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T>(
        &mut self,
        _name: &str,
        _variant_index: usize,
        variant: &str,
        value: T
    ) -> Result<()>
        where T: ser::Serialize,
    {
        self.doc = singleton_hash(try!(to_yaml(variant)),
                                  try!(to_yaml(value)));
        Ok(())
    }

    fn serialize_none(&mut self) -> Result<()> {
        self.serialize_unit()
    }

    fn serialize_some<V>(&mut self, value: V) -> Result<()>
        where V: ser::Serialize,
    {
        value.serialize(self)
    }

    fn serialize_seq(&mut self, len: Option<usize>) -> Result<()> {
        let vec = match len {
            None => yaml::Array::new(),
            Some(len) => yaml::Array::with_capacity(len),
        };
        self.doc = Yaml::Array(vec);
        Ok(())
    }

    fn serialize_seq_elt<T>(&mut self, _state: &mut(), elem: T) -> Result<()>
        where T: ser::Serialize,
    {
        if let Yaml::Array(ref mut vec) = self.doc {
            vec.push(try!(to_yaml(elem)));
        } else {
            panic!("bad call to serialize_seq_elt");
        }
        Ok(())
    }

    fn serialize_seq_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_seq_fixed_size(&mut self, len: usize) -> Result<()> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple(&mut self, len: usize) -> Result<()> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_elt<T>(&mut self, state: &mut(), elem: T) -> Result<()>
        where T: ser::Serialize,
    {
        self.serialize_seq_elt(state, elem)
    }

    fn serialize_tuple_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_tuple_struct(&mut self, _name: &'static str, len: usize) -> Result<()>
    {
        self.serialize_tuple(len)
    }

    fn serialize_tuple_struct_elt<V>(&mut self, state: &mut (), value: V) -> Result<()>
        where V: ser::Serialize,
    {
        self.serialize_tuple_elt(state, value)
    }

    fn serialize_tuple_struct_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_tuple_variant(
        &mut self,
        _enum: &'static str,
        _idx: usize,
        variant: &'static str,
        len: usize,
    ) -> Result<&'static str> {
        try!(self.serialize_tuple(len));
        Ok(variant)
    }

    fn serialize_tuple_variant_elt<V: ser::Serialize>(&mut self, _state: &mut &'static str, v: V) -> Result<()> {
        self.serialize_tuple_elt(&mut (), v)
    }

    fn serialize_tuple_variant_end(
        &mut self,
        variant: &'static str,
    ) -> Result<()> {
        self.doc = singleton_hash(try!(to_yaml(variant)), mem::replace(&mut self.doc, Yaml::Null));
        Ok(())
    }

    fn serialize_map(&mut self, _len: Option<usize>) -> Result<()>
    {
        self.doc = Yaml::Hash(yaml::Hash::new());
        Ok(())
    }

    fn serialize_map_elt<K, V>(&mut self, _state: &mut (), key: K, value: V) -> Result<()>
        where K: ser::Serialize,
              V: ser::Serialize,
    {
        if let Yaml::Hash(ref mut map) = self.doc {
            map.insert(try!(to_yaml(key)), try!(to_yaml(value)));
        } else {
            panic!("bad call to serialize_map_elt");
        }
        Ok(())
    }

    fn serialize_map_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_struct(&mut self, _name: &'static str, len: usize) -> Result<()>
    {
        self.serialize_map(Some(len))
    }

    fn serialize_struct_elt<V>(&mut self, state: &mut (), key: &'static str, value: V) -> Result<()>
        where V: ser::Serialize,
    {
        self.serialize_map_elt(state, key, value)
    }

    fn serialize_struct_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_struct_variant(
        &mut self,
        _enum: &'static str,
        _idx: usize,
        variant: &'static str,
        len: usize,
    ) -> Result<&'static str> {
        try!(self.serialize_struct(variant, len));
        Ok(variant)
    }

    fn serialize_struct_variant_elt<V: ser::Serialize>(&mut self, _state: &mut &'static str, field: &'static str, v: V) -> Result<()> {
        self.serialize_struct_elt(&mut (), field, v)
    }

    fn serialize_struct_variant_end(
        &mut self,
        variant: &'static str,
    ) -> Result<()> {
        self.doc = singleton_hash(try!(to_yaml(variant)), mem::replace(&mut self.doc, Yaml::Null));
        Ok(())
    }
}

pub fn to_writer<W, T>(writer: &mut W, value: &T) -> Result<()>
    where W: io::Write,
          T: ser::Serialize,
{
    let doc = try!(to_yaml(value));
    let mut writer_adapter = FmtToIoWriter {
        writer: writer,
    };
    try!(YamlEmitter::new(&mut writer_adapter).dump(&doc));
    Ok(())
}

pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
    where T: ser::Serialize,
{
    let mut vec = Vec::with_capacity(128);
    try!(to_writer(&mut vec, value));
    Ok(vec)
}

pub fn to_string<T>(value: &T) -> Result<String>
    where T: ser::Serialize,
{
    Ok(try!(String::from_utf8(try!(to_vec(value)))))
}

/// The yaml-rust library uses `fmt.Write` intead of `io.Write` so this is a
/// simple adapter.
struct FmtToIoWriter<'a, W>
    where W: io::Write + 'a,
{
    writer: &'a mut W,
}

impl<'a, W> fmt::Write for FmtToIoWriter<'a, W>
    where W: io::Write + 'a,
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        if self.writer.write(s.as_bytes()).is_err() {
            return Err(fmt::Error);
        }
        if self.writer.flush().is_err() {
            return Err(fmt::Error);
        }
        Ok(())
    }
}

fn to_yaml<T>(elem: T) -> Result<Yaml>
    where T: ser::Serialize,
{
    let mut ser = Serializer::new();
    try!(elem.serialize(&mut ser));
    Ok(ser.take())
}

fn singleton_hash(k: Yaml, v: Yaml) -> Yaml {
    let mut hash = yaml::Hash::new();
    hash.insert(k, v);
    Yaml::Hash(hash)
}
<commit_msg>Run cargo fmt<commit_after>// Copyright 2016 Serde YAML Developers
//
// 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.

//! YAML Serialization
//!
//! This module provides YAML serialization with the type `Serializer`.

use std::{fmt, io, mem};

use yaml_rust::{Yaml, YamlEmitter};
use yaml_rust::yaml;

use serde::ser;

use super::error::{Error, Result};

/// A structure for serializing a Rust value into a YAML value.
pub struct Serializer {
    /// The YAML value to hold the result.
    doc: Yaml,
}

impl Serializer {
    pub fn new() -> Self {
        Serializer {
            doc: Yaml::Null,
        }
    }

    pub fn take(self) -> Yaml {
        self.doc
    }
}

impl ser::Serializer for Serializer {
    type Error = Error;
    type SeqState = ();
    type TupleState = ();
    type TupleStructState = ();
    type TupleVariantState = &'static str;
    type MapState = ();
    type StructState = ();
    type StructVariantState = &'static str;

    fn serialize_bool(&mut self, v: bool) -> Result<()> {
        self.doc = Yaml::Boolean(v);
        Ok(())
    }

    fn serialize_isize(&mut self, v: isize) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i8(&mut self, v: i8) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i16(&mut self, v: i16) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i32(&mut self, v: i32) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i64(&mut self, v: i64) -> Result<()> {
        self.doc = Yaml::Integer(v);
        Ok(())
    }

    fn serialize_usize(&mut self, v: usize) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u8(&mut self, v: u8) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u16(&mut self, v: u16) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u32(&mut self, v: u32) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u64(&mut self, v: u64) -> Result<()> {
        self.serialize_i64(v as i64)
    }

    fn serialize_f32(&mut self, v: f32) -> Result<()> {
        self.doc = Yaml::Real(v.to_string());
        Ok(())
    }

    fn serialize_f64(&mut self, v: f64) -> Result<()> {
        self.doc = Yaml::Real(v.to_string());
        Ok(())
    }

    fn serialize_char(&mut self, value: char) -> Result<()> {
        self.doc = Yaml::String(value.to_string());
        Ok(())
    }

    fn serialize_str(&mut self, value: &str) -> Result<()> {
        self.doc = Yaml::String(String::from(value));
        Ok(())
    }

    fn serialize_bytes(&mut self, value: &[u8]) -> Result<()> {
        let mut state = try!(self.serialize_seq(Some(value.len())));
        for c in value {
            try!(self.serialize_seq_elt(&mut state, c));
        }
        self.serialize_seq_end(state)
    }

    fn serialize_unit(&mut self) -> Result<()> {
        self.doc = Yaml::Null;
        Ok(())
    }

    fn serialize_unit_struct(&mut self, _name: &'static str) -> Result<()> {
        self.doc = Yaml::Null;
        Ok(())
    }

    fn serialize_unit_variant(
        &mut self,
        _name: &str,
        _variant_index: usize,
        variant: &str
    ) -> Result<()> {
        self.doc = Yaml::String(String::from(variant));
        Ok(())
    }

    fn serialize_newtype_struct<T>(
        &mut self,
        _name: &'static str,
        value: T
    ) -> Result<()>
        where T: ser::Serialize,
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T>(
        &mut self,
        _name: &str,
        _variant_index: usize,
        variant: &str,
        value: T
    ) -> Result<()>
        where T: ser::Serialize,
    {
        self.doc = singleton_hash(try!(to_yaml(variant)), try!(to_yaml(value)));
        Ok(())
    }

    fn serialize_none(&mut self) -> Result<()> {
        self.serialize_unit()
    }

    fn serialize_some<V>(&mut self, value: V) -> Result<()>
        where V: ser::Serialize,
    {
        value.serialize(self)
    }

    fn serialize_seq(&mut self, len: Option<usize>) -> Result<()> {
        let vec = match len {
            None => yaml::Array::new(),
            Some(len) => yaml::Array::with_capacity(len),
        };
        self.doc = Yaml::Array(vec);
        Ok(())
    }

    fn serialize_seq_elt<T>(&mut self, _state: &mut (), elem: T) -> Result<()>
        where T: ser::Serialize,
    {
        if let Yaml::Array(ref mut vec) = self.doc {
            vec.push(try!(to_yaml(elem)));
        } else {
            panic!("bad call to serialize_seq_elt");
        }
        Ok(())
    }

    fn serialize_seq_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_seq_fixed_size(&mut self, len: usize) -> Result<()> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple(&mut self, len: usize) -> Result<()> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_elt<T>(&mut self, state: &mut (), elem: T) -> Result<()>
        where T: ser::Serialize,
    {
        self.serialize_seq_elt(state, elem)
    }

    fn serialize_tuple_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_tuple_struct(
        &mut self,
        _name: &'static str,
        len: usize
    ) -> Result<()> {
        self.serialize_tuple(len)
    }

    fn serialize_tuple_struct_elt<V>(
        &mut self,
        state: &mut (),
        value: V
    ) -> Result<()>
        where V: ser::Serialize,
    {
        self.serialize_tuple_elt(state, value)
    }

    fn serialize_tuple_struct_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_tuple_variant(
        &mut self,
        _enum: &'static str,
        _idx: usize,
        variant: &'static str,
        len: usize
    ) -> Result<&'static str> {
        try!(self.serialize_tuple(len));
        Ok(variant)
    }

    fn serialize_tuple_variant_elt<V: ser::Serialize>(
        &mut self,
        _state: &mut &'static str,
        v: V
    ) -> Result<()> {
        self.serialize_tuple_elt(&mut (), v)
    }

    fn serialize_tuple_variant_end(
        &mut self,
        variant: &'static str
    ) -> Result<()> {
        self.doc = singleton_hash(try!(to_yaml(variant)),
                                  mem::replace(&mut self.doc, Yaml::Null));
        Ok(())
    }

    fn serialize_map(&mut self, _len: Option<usize>) -> Result<()> {
        self.doc = Yaml::Hash(yaml::Hash::new());
        Ok(())
    }

    fn serialize_map_elt<K, V>(
        &mut self,
        _state: &mut (),
        key: K,
        value: V
    ) -> Result<()>
        where K: ser::Serialize,
              V: ser::Serialize,
    {
        if let Yaml::Hash(ref mut map) = self.doc {
            map.insert(try!(to_yaml(key)), try!(to_yaml(value)));
        } else {
            panic!("bad call to serialize_map_elt");
        }
        Ok(())
    }

    fn serialize_map_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_struct(
        &mut self,
        _name: &'static str,
        len: usize
    ) -> Result<()> {
        self.serialize_map(Some(len))
    }

    fn serialize_struct_elt<V>(
        &mut self,
        state: &mut (),
        key: &'static str,
        value: V
    ) -> Result<()>
        where V: ser::Serialize,
    {
        self.serialize_map_elt(state, key, value)
    }

    fn serialize_struct_end(&mut self, _state: ()) -> Result<()> {
        Ok(())
    }

    fn serialize_struct_variant(
        &mut self,
        _enum: &'static str,
        _idx: usize,
        variant: &'static str,
        len: usize
    ) -> Result<&'static str> {
        try!(self.serialize_struct(variant, len));
        Ok(variant)
    }

    fn serialize_struct_variant_elt<V: ser::Serialize>(
        &mut self,
        _state: &mut &'static str,
        field: &'static str,
        v: V
    ) -> Result<()> {
        self.serialize_struct_elt(&mut (), field, v)
    }

    fn serialize_struct_variant_end(
        &mut self,
        variant: &'static str
    ) -> Result<()> {
        self.doc = singleton_hash(try!(to_yaml(variant)),
                                  mem::replace(&mut self.doc, Yaml::Null));
        Ok(())
    }
}

pub fn to_writer<W, T>(writer: &mut W, value: &T) -> Result<()>
    where W: io::Write,
          T: ser::Serialize,
{
    let doc = try!(to_yaml(value));
    let mut writer_adapter = FmtToIoWriter {
        writer: writer,
    };
    try!(YamlEmitter::new(&mut writer_adapter).dump(&doc));
    Ok(())
}

pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
    where T: ser::Serialize,
{
    let mut vec = Vec::with_capacity(128);
    try!(to_writer(&mut vec, value));
    Ok(vec)
}

pub fn to_string<T>(value: &T) -> Result<String>
    where T: ser::Serialize,
{
    Ok(try!(String::from_utf8(try!(to_vec(value)))))
}

/// The yaml-rust library uses `fmt.Write` intead of `io.Write` so this is a
/// simple adapter.
struct FmtToIoWriter<'a, W>
    where W: io::Write + 'a,
{
    writer: &'a mut W,
}

impl<'a, W> fmt::Write for FmtToIoWriter<'a, W>
    where W: io::Write + 'a,
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        if self.writer.write(s.as_bytes()).is_err() {
            return Err(fmt::Error);
        }
        if self.writer.flush().is_err() {
            return Err(fmt::Error);
        }
        Ok(())
    }
}

fn to_yaml<T>(elem: T) -> Result<Yaml>
    where T: ser::Serialize,
{
    let mut ser = Serializer::new();
    try!(elem.serialize(&mut ser));
    Ok(ser.take())
}

fn singleton_hash(k: Yaml, v: Yaml) -> Yaml {
    let mut hash = yaml::Hash::new();
    hash.insert(k, v);
    Yaml::Hash(hash)
}
<|endoftext|>


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

use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
use resource_thread;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::path::PathBuf;
use std::thread;

const QUOTA_SIZE_LIMIT: usize = 5 * 1024 * 1024;

pub trait StorageThreadFactory {
    fn new(config_dir: Option<PathBuf>) -> Self;
}

impl StorageThreadFactory for IpcSender<StorageThreadMsg> {
    /// Create a storage thread
    fn new(config_dir: Option<PathBuf>) -> IpcSender<StorageThreadMsg> {
        let (chan, port) = ipc::channel().unwrap();
        thread::Builder::new().name("StorageManager".to_owned()).spawn(move || {
            StorageManager::new(port, config_dir).start();
        }).expect("Thread spawning failed");
        chan
    }
}

struct StorageManager {
    port: IpcReceiver<StorageThreadMsg>,
    session_data: HashMap<String, (usize, BTreeMap<String, String>)>,
    local_data: HashMap<String, (usize, BTreeMap<String, String>)>,
    config_dir: Option<PathBuf>,
}

impl StorageManager {
    fn new(port: IpcReceiver<StorageThreadMsg>,
           config_dir: Option<PathBuf>)
           -> StorageManager {
        let mut local_data = HashMap::new();
        if let Some(ref config_dir) = config_dir {
            resource_thread::read_json_from_file(&mut local_data, config_dir, "local_data.json");
        }
        StorageManager {
            port: port,
            session_data: HashMap::new(),
            local_data: local_data,
            config_dir: config_dir,
        }
    }
}

impl StorageManager {
    fn start(&mut self) {
        loop {
            match self.port.recv().unwrap() {
                StorageThreadMsg::Length(sender, url, storage_type) => {
                    self.length(sender, url, storage_type)
                }
                StorageThreadMsg::Key(sender, url, storage_type, index) => {
                    self.key(sender, url, storage_type, index)
                }
                StorageThreadMsg::Keys(sender, url, storage_type) => {
                    self.keys(sender, url, storage_type)
                }
                StorageThreadMsg::SetItem(sender, url, storage_type, name, value) => {
                    self.set_item(sender, url, storage_type, name, value)
                }
                StorageThreadMsg::GetItem(sender, url, storage_type, name) => {
                    self.request_item(sender, url, storage_type, name)
                }
                StorageThreadMsg::RemoveItem(sender, url, storage_type, name) => {
                    self.remove_item(sender, url, storage_type, name)
                }
                StorageThreadMsg::Clear(sender, url, storage_type) => {
                    self.clear(sender, url, storage_type)
                }
                StorageThreadMsg::Exit(sender) => {
                    if let Some(ref config_dir) = self.config_dir {
                        resource_thread::write_json_to_file(&self.local_data, config_dir, "local_data.json");
                    }
                    let _ = sender.send(());
                    break
                }
            }
        }
    }

    fn select_data(&self, storage_type: StorageType)
                   -> &HashMap<String, (usize, BTreeMap<String, String>)> {
        match storage_type {
            StorageType::Session => &self.session_data,
            StorageType::Local => &self.local_data
        }
    }

    fn select_data_mut(&mut self, storage_type: StorageType)
                       -> &mut HashMap<String, (usize, BTreeMap<String, String>)> {
        match storage_type {
            StorageType::Session => &mut self.session_data,
            StorageType::Local => &mut self.local_data
        }
    }

    fn length(&self, sender: IpcSender<usize>, url: ServoUrl, storage_type: StorageType) {
        let origin = self.origin_as_string(url);
        let data = self.select_data(storage_type);
        sender.send(data.get(&origin).map_or(0, |&(_, ref entry)| entry.len())).unwrap();
    }

    fn key(&self,
           sender: IpcSender<Option<String>>,
           url: ServoUrl,
           storage_type: StorageType,
           index: u32) {
        let origin = self.origin_as_string(url);
        let data = self.select_data(storage_type);
        let key = data.get(&origin)
                      .and_then(|&(_, ref entry)| entry.keys().nth(index as usize))
                      .cloned();
        sender.send(key).unwrap();
    }

    fn keys(&self,
            sender: IpcSender<Vec<String>>,
            url: ServoUrl,
            storage_type: StorageType) {
        let origin = self.origin_as_string(url);
        let data = self.select_data(storage_type);
        let keys = data.get(&origin)
                       .map_or(vec![], |&(_, ref entry)| entry.keys().cloned().collect());

        sender.send(keys).unwrap();
    }

    /// Sends Ok(changed, Some(old_value)) in case there was a previous
    /// value with the same key name but with different value name
    /// otherwise sends Err(()) to indicate that the operation would result in
    /// exceeding the quota limit
    fn set_item(&mut self,
                sender: IpcSender<Result<(bool, Option<String>), ()>>,
                url: ServoUrl,
                storage_type: StorageType,
                name: String,
                value: String) {
        let origin = self.origin_as_string(url);

        let (this_storage_size, other_storage_size) = {
            let local_data = self.select_data(StorageType::Local);
            let session_data = self.select_data(StorageType::Session);
            let local_data_size = local_data.get(&origin).map_or(0, |&(total, _)| total);
            let session_data_size = session_data.get(&origin).map_or(0, |&(total, _)| total);
            match storage_type {
                StorageType::Local => (local_data_size, session_data_size),
                StorageType::Session => (session_data_size, local_data_size),
            }
        };

        let data = self.select_data_mut(storage_type);
        if !data.contains_key(&origin) {
            data.insert(origin.clone(), (0, BTreeMap::new()));
        }

        let message = data.get_mut(&origin).map(|&mut (ref mut total, ref mut entry)| {
            let mut new_total_size = this_storage_size + value.as_bytes().len();
            if let Some(old_value) = entry.get(&name) {
                new_total_size -= old_value.as_bytes().len();
            } else {
                new_total_size += name.as_bytes().len();
            }

            if (new_total_size + other_storage_size) > QUOTA_SIZE_LIMIT {
                return Err(());
            }

            let message = entry.insert(name.clone(), value.clone()).map_or(
                Ok((true, None)),
                |old| if old == value {
                    Ok((false, None))
                } else {
                    Ok((true, Some(old)))
                });
            *total = new_total_size;
            message
        }).unwrap();
        sender.send(message).unwrap();
    }

    fn request_item(&self,
                sender: IpcSender<Option<String>>,
                url: ServoUrl,
                storage_type: StorageType,
                name: String) {
        let origin = self.origin_as_string(url);
        let data = self.select_data(storage_type);
        sender.send(data.get(&origin)
                    .and_then(|&(_, ref entry)| entry.get(&name))
                    .map(String::clone)).unwrap();
    }

    /// Sends Some(old_value) in case there was a previous value with the key name, otherwise sends None
    fn remove_item(&mut self,
                   sender: IpcSender<Option<String>>,
                   url: ServoUrl,
                   storage_type: StorageType,
                   name: String) {
        let origin = self.origin_as_string(url);
        let data = self.select_data_mut(storage_type);
        let old_value = data.get_mut(&origin).and_then(|&mut (ref mut total, ref mut entry)| {
            entry.remove(&name).and_then(|old| {
                *total -= name.as_bytes().len() + old.as_bytes().len();
                Some(old)
            })
        });
        sender.send(old_value).unwrap();
    }

    fn clear(&mut self, sender: IpcSender<bool>, url: ServoUrl, storage_type: StorageType) {
        let origin = self.origin_as_string(url);
        let data = self.select_data_mut(storage_type);
        sender.send(data.get_mut(&origin)
                    .map_or(false, |&mut (ref mut total, ref mut entry)| {
                        if !entry.is_empty() {
                            entry.clear();
                            *total = 0;
                            true
                        } else {
                            false
                        }})).unwrap();
    }

    fn origin_as_string(&self, url: ServoUrl) -> String {
        url.origin().ascii_serialization()
    }
}
<commit_msg>Auto merge of #20840 - fabricedesre:save-localstorage, r=Manishearth<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
use resource_thread;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::path::PathBuf;
use std::thread;

const QUOTA_SIZE_LIMIT: usize = 5 * 1024 * 1024;

pub trait StorageThreadFactory {
    fn new(config_dir: Option<PathBuf>) -> Self;
}

impl StorageThreadFactory for IpcSender<StorageThreadMsg> {
    /// Create a storage thread
    fn new(config_dir: Option<PathBuf>) -> IpcSender<StorageThreadMsg> {
        let (chan, port) = ipc::channel().unwrap();
        thread::Builder::new().name("StorageManager".to_owned()).spawn(move || {
            StorageManager::new(port, config_dir).start();
        }).expect("Thread spawning failed");
        chan
    }
}

struct StorageManager {
    port: IpcReceiver<StorageThreadMsg>,
    session_data: HashMap<String, (usize, BTreeMap<String, String>)>,
    local_data: HashMap<String, (usize, BTreeMap<String, String>)>,
    config_dir: Option<PathBuf>,
}

impl StorageManager {
    fn new(port: IpcReceiver<StorageThreadMsg>,
           config_dir: Option<PathBuf>)
           -> StorageManager {
        let mut local_data = HashMap::new();
        if let Some(ref config_dir) = config_dir {
            resource_thread::read_json_from_file(&mut local_data, config_dir, "local_data.json");
        }
        StorageManager {
            port: port,
            session_data: HashMap::new(),
            local_data: local_data,
            config_dir: config_dir,
        }
    }
}

impl StorageManager {
    fn start(&mut self) {
        loop {
            match self.port.recv().unwrap() {
                StorageThreadMsg::Length(sender, url, storage_type) => {
                    self.length(sender, url, storage_type)
                }
                StorageThreadMsg::Key(sender, url, storage_type, index) => {
                    self.key(sender, url, storage_type, index)
                }
                StorageThreadMsg::Keys(sender, url, storage_type) => {
                    self.keys(sender, url, storage_type)
                }
                StorageThreadMsg::SetItem(sender, url, storage_type, name, value) => {
                    self.set_item(sender, url, storage_type, name, value);
                    self.save_state()
                }
                StorageThreadMsg::GetItem(sender, url, storage_type, name) => {
                    self.request_item(sender, url, storage_type, name)
                }
                StorageThreadMsg::RemoveItem(sender, url, storage_type, name) => {
                    self.remove_item(sender, url, storage_type, name);
                    self.save_state()
                }
                StorageThreadMsg::Clear(sender, url, storage_type) => {
                    self.clear(sender, url, storage_type);
                    self.save_state()
                }
                StorageThreadMsg::Exit(sender) => {
                    // Nothing to do since we save localstorage set eagerly.
                    let _ = sender.send(());
                    break
                }
            }
        }
    }

    fn save_state(&self) {
        if let Some(ref config_dir) = self.config_dir {
            resource_thread::write_json_to_file(&self.local_data, config_dir, "local_data.json");
        }
    }

    fn select_data(&self, storage_type: StorageType)
                   -> &HashMap<String, (usize, BTreeMap<String, String>)> {
        match storage_type {
            StorageType::Session => &self.session_data,
            StorageType::Local => &self.local_data
        }
    }

    fn select_data_mut(&mut self, storage_type: StorageType)
                       -> &mut HashMap<String, (usize, BTreeMap<String, String>)> {
        match storage_type {
            StorageType::Session => &mut self.session_data,
            StorageType::Local => &mut self.local_data
        }
    }

    fn length(&self, sender: IpcSender<usize>, url: ServoUrl, storage_type: StorageType) {
        let origin = self.origin_as_string(url);
        let data = self.select_data(storage_type);
        sender.send(data.get(&origin).map_or(0, |&(_, ref entry)| entry.len())).unwrap();
    }

    fn key(&self,
           sender: IpcSender<Option<String>>,
           url: ServoUrl,
           storage_type: StorageType,
           index: u32) {
        let origin = self.origin_as_string(url);
        let data = self.select_data(storage_type);
        let key = data.get(&origin)
                      .and_then(|&(_, ref entry)| entry.keys().nth(index as usize))
                      .cloned();
        sender.send(key).unwrap();
    }

    fn keys(&self,
            sender: IpcSender<Vec<String>>,
            url: ServoUrl,
            storage_type: StorageType) {
        let origin = self.origin_as_string(url);
        let data = self.select_data(storage_type);
        let keys = data.get(&origin)
                       .map_or(vec![], |&(_, ref entry)| entry.keys().cloned().collect());

        sender.send(keys).unwrap();
    }

    /// Sends Ok(changed, Some(old_value)) in case there was a previous
    /// value with the same key name but with different value name
    /// otherwise sends Err(()) to indicate that the operation would result in
    /// exceeding the quota limit
    fn set_item(&mut self,
                sender: IpcSender<Result<(bool, Option<String>), ()>>,
                url: ServoUrl,
                storage_type: StorageType,
                name: String,
                value: String) {
        let origin = self.origin_as_string(url);

        let (this_storage_size, other_storage_size) = {
            let local_data = self.select_data(StorageType::Local);
            let session_data = self.select_data(StorageType::Session);
            let local_data_size = local_data.get(&origin).map_or(0, |&(total, _)| total);
            let session_data_size = session_data.get(&origin).map_or(0, |&(total, _)| total);
            match storage_type {
                StorageType::Local => (local_data_size, session_data_size),
                StorageType::Session => (session_data_size, local_data_size),
            }
        };

        let data = self.select_data_mut(storage_type);
        if !data.contains_key(&origin) {
            data.insert(origin.clone(), (0, BTreeMap::new()));
        }

        let message = data.get_mut(&origin).map(|&mut (ref mut total, ref mut entry)| {
            let mut new_total_size = this_storage_size + value.as_bytes().len();
            if let Some(old_value) = entry.get(&name) {
                new_total_size -= old_value.as_bytes().len();
            } else {
                new_total_size += name.as_bytes().len();
            }

            if (new_total_size + other_storage_size) > QUOTA_SIZE_LIMIT {
                return Err(());
            }

            let message = entry.insert(name.clone(), value.clone()).map_or(
                Ok((true, None)),
                |old| if old == value {
                    Ok((false, None))
                } else {
                    Ok((true, Some(old)))
                });
            *total = new_total_size;
            message
        }).unwrap();
        sender.send(message).unwrap();
    }

    fn request_item(&self,
                sender: IpcSender<Option<String>>,
                url: ServoUrl,
                storage_type: StorageType,
                name: String) {
        let origin = self.origin_as_string(url);
        let data = self.select_data(storage_type);
        sender.send(data.get(&origin)
                    .and_then(|&(_, ref entry)| entry.get(&name))
                    .map(String::clone)).unwrap();
    }

    /// Sends Some(old_value) in case there was a previous value with the key name, otherwise sends None
    fn remove_item(&mut self,
                   sender: IpcSender<Option<String>>,
                   url: ServoUrl,
                   storage_type: StorageType,
                   name: String) {
        let origin = self.origin_as_string(url);
        let data = self.select_data_mut(storage_type);
        let old_value = data.get_mut(&origin).and_then(|&mut (ref mut total, ref mut entry)| {
            entry.remove(&name).and_then(|old| {
                *total -= name.as_bytes().len() + old.as_bytes().len();
                Some(old)
            })
        });
        sender.send(old_value).unwrap();
    }

    fn clear(&mut self, sender: IpcSender<bool>, url: ServoUrl, storage_type: StorageType) {
        let origin = self.origin_as_string(url);
        let data = self.select_data_mut(storage_type);
        sender.send(data.get_mut(&origin)
                    .map_or(false, |&mut (ref mut total, ref mut entry)| {
                        if !entry.is_empty() {
                            entry.clear();
                            *total = 0;
                            true
                        } else {
                            false
                        }})).unwrap();
    }

    fn origin_as_string(&self, url: ServoUrl) -> String {
        url.origin().ascii_serialization()
    }
}
<|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;
use rustc::mir::repr::*;
use rustc::middle::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use std::io::{self, Write};
use syntax::ast::NodeId;
use syntax::codemap::Span;

const INDENT: &'static str = "    ";

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

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

pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>,
                          node_id: NodeId,
                          mir: &Mir<'tcx>,
                          w: &mut Write,
                          annotations: &FnvHashMap<Location, Vec<Annotation>>)
                          -> io::Result<()> {
    write_mir_intro(tcx, node_id, mir, w)?;
    for block in mir.all_basic_blocks() {
        write_basic_block(tcx, block, mir, w, annotations)?;
    }

    // construct a scope tree
    let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap();
    for (index, scope_data) in mir.scopes.vec.iter().enumerate() {
        scope_tree.entry(scope_data.parent_scope)
                  .or_insert(vec![])
                  .push(ScopeId::new(index));
    }
    write_scope_tree(tcx, mir, &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(),
             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,
                    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())?;
        }
        writeln!(w, "{0:1$}Extent: {2:?}",
                 "", indent,
                 tcx.region_maps.code_extent_data(data.extent))?;
        write_scope_tree(tcx, mir, 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(tcx: &TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write)
                   -> io::Result<()> {
    write!(w, "fn {}(", tcx.map.path_to_string(nid))?;

    // 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, "!")?,
    }

    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, "{:?}: {}; // {}", Lvalue::Var(i as u32), var.ty, var.name)?;
    }

    // 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>adjust pretty printer to print scopes / auxiliary<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, ScopeAuxiliary};
use rustc::mir::repr::*;
use rustc::middle::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use std::io::{self, Write};
use syntax::ast::NodeId;
use syntax::codemap::Span;

const INDENT: &'static str = "    ";

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

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

pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>,
                          node_id: NodeId,
                          mir: &Mir<'tcx>,
                          w: &mut Write,
                          auxiliary: Option<&Vec<ScopeAuxiliary>>)
                          -> io::Result<()> {
    // compute scope/entry exit annotations
    let mut annotations = FnvHashMap();
    if let Some(auxiliary) = auxiliary {
        for (index, auxiliary) in auxiliary.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, node_id, 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.vec.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(),
             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<&Vec<ScopeAuxiliary>>,
                    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.index()].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(tcx: &TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write)
                   -> io::Result<()> {
    write!(w, "fn {}(", tcx.map.path_to_string(nid))?;

    // 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, "!")?,
    }

    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, "{:?}: {}; // {}", Lvalue::Var(i as u32), var.ty, var.name)?;
    }

    // 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(())
}
<|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.

//! Unwind library interface

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)] // these are just bindings

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
pub use self::_Unwind_Action::*;
#[cfg(target_arch = "arm")]
pub use self::_Unwind_State::*;
pub use self::_Unwind_Reason_Code::*;

use core::kinds::Copy;
use libc;

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
#[repr(C)]
#[deriving(Copy)]
pub enum _Unwind_Action {
    _UA_SEARCH_PHASE = 1,
    _UA_CLEANUP_PHASE = 2,
    _UA_HANDLER_FRAME = 4,
    _UA_FORCE_UNWIND = 8,
    _UA_END_OF_STACK = 16,
}

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
impl Copy for _Unwind_Action {}

#[cfg(target_arch = "arm")]
#[repr(C)]
pub enum _Unwind_State {
    _US_VIRTUAL_UNWIND_FRAME = 0,
    _US_UNWIND_FRAME_STARTING = 1,
    _US_UNWIND_FRAME_RESUME = 2,
    _US_ACTION_MASK = 3,
    _US_FORCE_UNWIND = 8,
    _US_END_OF_STACK = 16
}

#[repr(C)]
pub enum _Unwind_Reason_Code {
    _URC_NO_REASON = 0,
    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
    _URC_FATAL_PHASE2_ERROR = 2,
    _URC_FATAL_PHASE1_ERROR = 3,
    _URC_NORMAL_STOP = 4,
    _URC_END_OF_STACK = 5,
    _URC_HANDLER_FOUND = 6,
    _URC_INSTALL_CONTEXT = 7,
    _URC_CONTINUE_UNWIND = 8,
    _URC_FAILURE = 9, // used only by ARM EABI
}

pub type _Unwind_Exception_Class = u64;

pub type _Unwind_Word = libc::uintptr_t;

#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: uint = 5;

#[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: uint = 6;

#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
pub const unwinder_private_data_size: uint = 20;

#[cfg(all(target_arch = "arm", target_os = "ios"))]
pub const unwinder_private_data_size: uint = 5;

#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
pub const unwinder_private_data_size: uint = 2;

#[repr(C)]
pub struct _Unwind_Exception {
    pub exception_class: _Unwind_Exception_Class,
    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
    pub private: [_Unwind_Word, ..unwinder_private_data_size],
}

pub enum _Unwind_Context {}

pub type _Unwind_Exception_Cleanup_Fn =
        extern "C" fn(unwind_code: _Unwind_Reason_Code,
                      exception: *mut _Unwind_Exception);

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[link(name = "gcc_s")]
extern {}

#[cfg(target_os = "android")]
#[link(name = "gcc")]
extern {}

#[cfg(target_os = "dragonfly")]
#[link(name = "gcc_pic")]
extern {}

extern "C" {
    // iOS on armv7 uses SjLj exceptions and requires to link
    // against corresponding routine (..._SjLj_...)
    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
                                  -> _Unwind_Reason_Code;

    #[cfg(all(target_os = "ios", target_arch = "arm"))]
    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
                                   -> _Unwind_Reason_Code;

    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
}

// ... and now we just providing access to SjLj counterspart
// through a standard name to hide those details from others
// (see also comment above regarding _Unwind_RaiseException)
#[cfg(all(target_os = "ios", target_arch = "arm"))]
#[inline(always)]
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
                                     -> _Unwind_Reason_Code {
    _Unwind_SjLj_RaiseException(exc)
}
<commit_msg>Better fix for OIBIT<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.

//! Unwind library interface

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)] // these are just bindings

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
pub use self::_Unwind_Action::*;
#[cfg(target_arch = "arm")]
pub use self::_Unwind_State::*;
pub use self::_Unwind_Reason_Code::*;

use libc;

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
#[repr(C)]
#[deriving(Copy)]
pub enum _Unwind_Action {
    _UA_SEARCH_PHASE = 1,
    _UA_CLEANUP_PHASE = 2,
    _UA_HANDLER_FRAME = 4,
    _UA_FORCE_UNWIND = 8,
    _UA_END_OF_STACK = 16,
}

#[cfg(target_arch = "arm")]
#[repr(C)]
pub enum _Unwind_State {
    _US_VIRTUAL_UNWIND_FRAME = 0,
    _US_UNWIND_FRAME_STARTING = 1,
    _US_UNWIND_FRAME_RESUME = 2,
    _US_ACTION_MASK = 3,
    _US_FORCE_UNWIND = 8,
    _US_END_OF_STACK = 16
}

#[repr(C)]
pub enum _Unwind_Reason_Code {
    _URC_NO_REASON = 0,
    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
    _URC_FATAL_PHASE2_ERROR = 2,
    _URC_FATAL_PHASE1_ERROR = 3,
    _URC_NORMAL_STOP = 4,
    _URC_END_OF_STACK = 5,
    _URC_HANDLER_FOUND = 6,
    _URC_INSTALL_CONTEXT = 7,
    _URC_CONTINUE_UNWIND = 8,
    _URC_FAILURE = 9, // used only by ARM EABI
}

pub type _Unwind_Exception_Class = u64;

pub type _Unwind_Word = libc::uintptr_t;

#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: uint = 5;

#[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: uint = 6;

#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
pub const unwinder_private_data_size: uint = 20;

#[cfg(all(target_arch = "arm", target_os = "ios"))]
pub const unwinder_private_data_size: uint = 5;

#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
pub const unwinder_private_data_size: uint = 2;

#[repr(C)]
pub struct _Unwind_Exception {
    pub exception_class: _Unwind_Exception_Class,
    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
    pub private: [_Unwind_Word, ..unwinder_private_data_size],
}

pub enum _Unwind_Context {}

pub type _Unwind_Exception_Cleanup_Fn =
        extern "C" fn(unwind_code: _Unwind_Reason_Code,
                      exception: *mut _Unwind_Exception);

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[link(name = "gcc_s")]
extern {}

#[cfg(target_os = "android")]
#[link(name = "gcc")]
extern {}

#[cfg(target_os = "dragonfly")]
#[link(name = "gcc_pic")]
extern {}

extern "C" {
    // iOS on armv7 uses SjLj exceptions and requires to link
    // against corresponding routine (..._SjLj_...)
    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
                                  -> _Unwind_Reason_Code;

    #[cfg(all(target_os = "ios", target_arch = "arm"))]
    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
                                   -> _Unwind_Reason_Code;

    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
}

// ... and now we just providing access to SjLj counterspart
// through a standard name to hide those details from others
// (see also comment above regarding _Unwind_RaiseException)
#[cfg(all(target_os = "ios", target_arch = "arm"))]
#[inline(always)]
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
                                     -> _Unwind_Reason_Code {
    _Unwind_SjLj_RaiseException(exc)
}
<|endoftext|>