<commit_before>use super::{
    EdgeType,
    Incoming,
};
use super::graph::{
    Graph,
    IndexType,
    NodeIndex,
};

#[derive(Debug)]
struct Vf2State<Ix, Ty> {
    /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
    /// NodeIndex::end() for no mapping.
    core: Vec<NodeIndex<Ix>>,
    /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
    /// These are all the next vertices that are not mapped yet, but
    /// have an outgoing edge from the mapping.
    out: Vec<usize>,
    /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
    /// These are all the incoming vertices, those not mapped yet, but
    /// have an edge from them into the mapping.
    /// Unused if graph is undirected -- it's identical with out in that case.
    ins: Vec<usize>,
    generation: usize,
}

impl<Ix, Ty> Vf2State<Ix, Ty> where Ix: IndexType, Ty: EdgeType,
{
    pub fn new(c0: usize) -> Self
    {
        let mut state = Vf2State {
            core: Vec::with_capacity(c0),
            ins: Vec::with_capacity(c0 * <Ty as EdgeType>::is_directed() as usize),
            out: Vec::with_capacity(c0),
            generation: 0,
        };
        for _ in (0..c0) {
            state.core.push(NodeIndex::end());
            state.out.push(0);
            if <Ty as EdgeType>::is_directed() {
                state.ins.push(0);
            }
        }
        state
    }

    /// Return **true** if we have a complete mapping
    pub fn is_complete(&self) -> bool
    {
        self.generation == self.core.len()
    }

    /// Add mapping **from** <-> **to** to the state.
    pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
                              g: &Graph<N, E, Ty, Ix>)
    {
        self.generation += 1;
        let s = self.generation;
        self.core[from.index()] = to;
        // update T0 & T1 ins/outs
        // T0out: Node in G0 not in M0 but successor of a node in M0.
        // st.out[0]: Node either in M0 or successor of M0
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == 0 {
                self.out[ix.index()] = s;
            }
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == 0 {
                    self.ins[ix.index()] = s;
                }
            }
        }
    }

    /// Restore the state to before the last added mapping
    pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
                             g: &Graph<N, E, Ty, Ix>)
    {
        let s = self.generation;
        self.generation -= 1;

        // undo (n, m) mapping
        self.core[from.index()] = NodeIndex::end();

        // unmark in ins and outs
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == s {
                self.out[ix.index()] = 0;
            }
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == s {
                    self.ins[ix.index()] = 0;
                }
            }
        }
    }

    /// Find the next (least) node in the Tout set.
    pub fn next_out_index(&self, from_index: usize) -> Option<usize>
    {
        self.out[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.core[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the Tin set.
    pub fn next_in_index(&self, from_index: usize) -> Option<usize>
    {
        if !<Ty as EdgeType>::is_directed() {
            return None
        }
        self.ins[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.core[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the N - M set.
    pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
    {
        self.core[from_index..].iter()
               .enumerate()
               .filter(|&(_, elt)| *elt == NodeIndex::end())
               .next()
               .map(|(index, _)| index)
    }
}

/// Return **true** if the graphs **g0** and **g1** are isomorphic.
///
/// Using the VF2 algorithm.
///
/// Not implemented: Vertex or edge weight matching.
///
/// ## References
///
/// * A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs
///   Luigi P. Cordella, Pasquale Foggia, Carlo Sansone,
///   and Mario Vento
pub fn is_isomorphic<N, E, Ix, Ty>(g0: &Graph<N, E, Ty, Ix>,
                                   g1: &Graph<N, E, Ty, Ix>) -> bool where
    Ix: IndexType,
    Ty: EdgeType,
{
    if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
        return false
    }

    /// Return Some(bool) if isomorphism is decided, else None.
    fn try_match<N, E, Ix, Ty>(st: &mut [Vf2State<Ix, Ty>; 2],
                               g0: &Graph<N, E, Ty, Ix>,
                               g1: &Graph<N, E, Ty, Ix>) -> Option<bool> where
        Ix: IndexType,
        Ty: EdgeType,
    {
        let g = [g0, g1];
        let graph_indices = 0..2us;
        let end = NodeIndex::end();

        // if all are mapped -- we are done and have an iso
        if st[0].is_complete() {
            return Some(true)
        }

        // A "depth first" search of a valid mapping from graph 1 to graph 2

        // F(s, n, m) -- evaluate state s and add mapping n <-> m

        // Find least T1out node (in st.out[1] but not in M[1])
        #[derive(Copy, Clone, PartialEq, Debug)]
        enum OpenList {
            Out,
            In,
            Other,
        }
        let mut open_list = OpenList::Out;

        let mut to_index;
        let mut from_index = None;
        // Try the out list
        to_index = st[1].next_out_index(0);

        if to_index.is_some() {
            from_index = st[0].next_out_index(0);
            open_list = OpenList::Out;
        }

        // Try the in list
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_in_index(0);

            if to_index.is_some() {
                from_index = st[0].next_in_index(0);
                open_list = OpenList::In;
            }
        }

        // Try the other list -- disconnected graph
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_rest_index(0);
            if to_index.is_some() {
                from_index = st[0].next_rest_index(0);
                open_list = OpenList::Other;
            }
        }

        let (cand0, cand1) = match (from_index, to_index) {
            (Some(n), Some(m)) => (n, m),
            // No more candidates
            _ => return None,
        };

        let mut nx = NodeIndex::new(cand0);
        let mx = NodeIndex::new(cand1);

        let mut first = true;

        'candidates: loop {
            if !first {
                // Find the next node index to try on the `from` side of the mapping
                let start = nx.index() + 1;
                let cand0 = match open_list {
                    OpenList::Out => st[0].next_out_index(start),
                    OpenList::In => st[0].next_in_index(start),
                    OpenList::Other => st[0].next_rest_index(start),
                }.map(|c| c + start); // compensate for start offset.
                nx = match cand0 {
                    None => break, // no more candidates
                    Some(ix) => NodeIndex::new(ix),
                };
                debug_assert!(nx.index() >= start);
            }
            first = false;

            let nodes = [nx, mx];

            /*
            print!("Mapping state: ");
            for (index, nmap) in st.core[0].iter().enumerate() {
                if *nmap == end {
                    continue;
                }
                print!("{} => {}, ", index, nmap.index());
            }
            println!("{} => {}", nx.index(), mx.index());
            */

            // Check syntactic feasibility of mapping by ensuring adjacencies
            // of nx map to adjacencies of mx.
            //
            // nx == map to => mx
            //
            // R_succ
            //
            // Check that every neighbor of nx is mapped to a neighbor of mx,
            // then check the reverse, from mx to nx. Check that they have the same
            // count of edges.
            let mut succ_count = [0, 0];
            for j in graph_indices.clone() {
                for n_neigh in g[j].neighbors(nodes[j]) {
                    succ_count[j] += 1;
                    let m_neigh = st[j].core[n_neigh.index()];
                    if m_neigh == end {
                        continue;
                    }
                    let has_edge = g[1-j].find_edge(nodes[1-j], m_neigh).is_some();
                    if !has_edge {
                        continue 'candidates;
                    }
                }
            }
            if succ_count[0] != succ_count[1] {
                continue 'candidates;
            }

            // R_pred
            if g[0].is_directed() {
                let mut pred_count = [0, 0];
                for j in graph_indices.clone() {
                    for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
                        pred_count[j] += 1;
                        let m_neigh = st[j].core[n_neigh.index()];
                        if m_neigh == end {
                            continue;
                        }
                        let has_edge = g[1-j].find_edge(m_neigh, nodes[1-j]).is_some();
                        if !has_edge {
                            continue 'candidates;
                        }
                    }
                }
                if pred_count[0] != pred_count[1] {
                    continue 'candidates;
                }
            }

            // Check cardinalities of open sets, important to prune
            // the search tree.
            //
            // counts in Tin/Tout
            let t0in = st[0].ins.iter().filter(|&&x| x > 0).count();
            let t1in = st[1].ins.iter().filter(|&&x| x > 0).count();
            let t0out = st[0].out.iter().filter(|&&x| x > 0).count();
            let t1out = st[1].out.iter().filter(|&&x| x > 0).count();
            if t0in != t1in || t0out != t1out {
                continue 'candidates;
            }

            // counts in N0 - M0 - Tin - Tout
            // equal to count in N - ins - outs
            let n0 = st[0].ins.iter().zip(st[0].out.iter())
                        .filter(|&(&a, &b)| a == 0 && b == 0)
                        .count();
            let n1 = st[1].ins.iter().zip(st[1].out.iter())
                        .filter(|&(&a, &b)| a == 0 && b == 0)
                        .count();

            if n0 != n1 {
                continue 'candidates;
            }

            // Add mapping nx <-> mx to the state
            for j in graph_indices.clone() {
                st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
            }

            // Recurse
            match try_match(st, g0, g1) {
                None => {}
                result => return result,
            }

            // Restore state.
            for j in graph_indices.clone() {
                st[j].pop_mapping(nodes[j], g[j]);
            }
        }
        None
    }
    let mut st = [Vf2State::new(g0.node_count()),
                  Vf2State::new(g1.node_count())];
    try_match(&mut st, g0, g1).unwrap_or(false)
}

<commit_msg>Rename core → mapping<commit_after>use super::{
    EdgeType,
    Incoming,
};
use super::graph::{
    Graph,
    IndexType,
    NodeIndex,
};

#[derive(Debug)]
struct Vf2State<Ix, Ty> {
    /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
    /// NodeIndex::end() for no mapping.
    mapping: Vec<NodeIndex<Ix>>,
    /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
    /// These are all the next vertices that are not mapped yet, but
    /// have an outgoing edge from the mapping.
    out: Vec<usize>,
    /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
    /// These are all the incoming vertices, those not mapped yet, but
    /// have an edge from them into the mapping.
    /// Unused if graph is undirected -- it's identical with out in that case.
    ins: Vec<usize>,
    generation: usize,
}

impl<Ix, Ty> Vf2State<Ix, Ty> where Ix: IndexType, Ty: EdgeType,
{
    pub fn new(c0: usize) -> Self
    {
        let mut state = Vf2State {
            mapping: Vec::with_capacity(c0),
            out: Vec::with_capacity(c0),
            ins: Vec::with_capacity(c0 * <Ty as EdgeType>::is_directed() as usize),
            generation: 0,
        };
        for _ in (0..c0) {
            state.mapping.push(NodeIndex::end());
            state.out.push(0);
            if <Ty as EdgeType>::is_directed() {
                state.ins.push(0);
            }
        }
        state
    }

    /// Return **true** if we have a complete mapping
    pub fn is_complete(&self) -> bool
    {
        self.generation == self.mapping.len()
    }

    /// Add mapping **from** <-> **to** to the state.
    pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
                              g: &Graph<N, E, Ty, Ix>)
    {
        self.generation += 1;
        let s = self.generation;
        self.mapping[from.index()] = to;
        // update T0 & T1 ins/outs
        // T0out: Node in G0 not in M0 but successor of a node in M0.
        // st.out[0]: Node either in M0 or successor of M0
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == 0 {
                self.out[ix.index()] = s;
            }
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == 0 {
                    self.ins[ix.index()] = s;
                }
            }
        }
    }

    /// Restore the state to before the last added mapping
    pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
                             g: &Graph<N, E, Ty, Ix>)
    {
        let s = self.generation;
        self.generation -= 1;

        // undo (n, m) mapping
        self.mapping[from.index()] = NodeIndex::end();

        // unmark in ins and outs
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == s {
                self.out[ix.index()] = 0;
            }
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == s {
                    self.ins[ix.index()] = 0;
                }
            }
        }
    }

    /// Find the next (least) node in the Tout set.
    pub fn next_out_index(&self, from_index: usize) -> Option<usize>
    {
        self.out[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the Tin set.
    pub fn next_in_index(&self, from_index: usize) -> Option<usize>
    {
        if !<Ty as EdgeType>::is_directed() {
            return None
        }
        self.ins[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the N - M set.
    pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
    {
        self.mapping[from_index..].iter()
               .enumerate()
               .filter(|&(_, elt)| *elt == NodeIndex::end())
               .next()
               .map(|(index, _)| index)
    }
}

/// Return **true** if the graphs **g0** and **g1** are isomorphic.
///
/// Using the VF2 algorithm.
///
/// Not implemented: Vertex or edge weight matching.
///
/// ## References
///
/// * A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs
///   Luigi P. Cordella, Pasquale Foggia, Carlo Sansone,
///   and Mario Vento
pub fn is_isomorphic<N, E, Ix, Ty>(g0: &Graph<N, E, Ty, Ix>,
                                   g1: &Graph<N, E, Ty, Ix>) -> bool where
    Ix: IndexType,
    Ty: EdgeType,
{
    if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
        return false
    }

    /// Return Some(bool) if isomorphism is decided, else None.
    fn try_match<N, E, Ix, Ty>(st: &mut [Vf2State<Ix, Ty>; 2],
                               g0: &Graph<N, E, Ty, Ix>,
                               g1: &Graph<N, E, Ty, Ix>) -> Option<bool> where
        Ix: IndexType,
        Ty: EdgeType,
    {
        let g = [g0, g1];
        let graph_indices = 0..2us;
        let end = NodeIndex::end();

        // if all are mapped -- we are done and have an iso
        if st[0].is_complete() {
            return Some(true)
        }

        // A "depth first" search of a valid mapping from graph 1 to graph 2

        // F(s, n, m) -- evaluate state s and add mapping n <-> m

        // Find least T1out node (in st.out[1] but not in M[1])
        #[derive(Copy, Clone, PartialEq, Debug)]
        enum OpenList {
            Out,
            In,
            Other,
        }
        let mut open_list = OpenList::Out;

        let mut to_index;
        let mut from_index = None;
        // Try the out list
        to_index = st[1].next_out_index(0);

        if to_index.is_some() {
            from_index = st[0].next_out_index(0);
            open_list = OpenList::Out;
        }

        // Try the in list
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_in_index(0);

            if to_index.is_some() {
                from_index = st[0].next_in_index(0);
                open_list = OpenList::In;
            }
        }

        // Try the other list -- disconnected graph
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_rest_index(0);
            if to_index.is_some() {
                from_index = st[0].next_rest_index(0);
                open_list = OpenList::Other;
            }
        }

        let (cand0, cand1) = match (from_index, to_index) {
            (Some(n), Some(m)) => (n, m),
            // No more candidates
            _ => return None,
        };

        let mut nx = NodeIndex::new(cand0);
        let mx = NodeIndex::new(cand1);

        let mut first = true;

        'candidates: loop {
            if !first {
                // Find the next node index to try on the `from` side of the mapping
                let start = nx.index() + 1;
                let cand0 = match open_list {
                    OpenList::Out => st[0].next_out_index(start),
                    OpenList::In => st[0].next_in_index(start),
                    OpenList::Other => st[0].next_rest_index(start),
                }.map(|c| c + start); // compensate for start offset.
                nx = match cand0 {
                    None => break, // no more candidates
                    Some(ix) => NodeIndex::new(ix),
                };
                debug_assert!(nx.index() >= start);
            }
            first = false;

            let nodes = [nx, mx];

            /*
            print!("Mapping state: ");
            for (index, nmap) in st.mapping[0].iter().enumerate() {
                if *nmap == end {
                    continue;
                }
                print!("{} => {}, ", index, nmap.index());
            }
            println!("{} => {}", nx.index(), mx.index());
            */

            // Check syntactic feasibility of mapping by ensuring adjacencies
            // of nx map to adjacencies of mx.
            //
            // nx == map to => mx
            //
            // R_succ
            //
            // Check that every neighbor of nx is mapped to a neighbor of mx,
            // then check the reverse, from mx to nx. Check that they have the same
            // count of edges.
            let mut succ_count = [0, 0];
            for j in graph_indices.clone() {
                for n_neigh in g[j].neighbors(nodes[j]) {
                    succ_count[j] += 1;
                    let m_neigh = st[j].mapping[n_neigh.index()];
                    if m_neigh == end {
                        continue;
                    }
                    let has_edge = g[1-j].find_edge(nodes[1-j], m_neigh).is_some();
                    if !has_edge {
                        continue 'candidates;
                    }
                }
            }
            if succ_count[0] != succ_count[1] {
                continue 'candidates;
            }

            // R_pred
            if g[0].is_directed() {
                let mut pred_count = [0, 0];
                for j in graph_indices.clone() {
                    for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
                        pred_count[j] += 1;
                        let m_neigh = st[j].mapping[n_neigh.index()];
                        if m_neigh == end {
                            continue;
                        }
                        let has_edge = g[1-j].find_edge(m_neigh, nodes[1-j]).is_some();
                        if !has_edge {
                            continue 'candidates;
                        }
                    }
                }
                if pred_count[0] != pred_count[1] {
                    continue 'candidates;
                }
            }

            // Check cardinalities of open sets, important to prune
            // the search tree.
            //
            // counts in Tin/Tout
            let t0in = st[0].ins.iter().filter(|&&x| x > 0).count();
            let t1in = st[1].ins.iter().filter(|&&x| x > 0).count();
            let t0out = st[0].out.iter().filter(|&&x| x > 0).count();
            let t1out = st[1].out.iter().filter(|&&x| x > 0).count();
            if t0in != t1in || t0out != t1out {
                continue 'candidates;
            }

            // counts in N0 - M0 - Tin - Tout
            // equal to count in N - ins - outs
            let n0 = st[0].ins.iter().zip(st[0].out.iter())
                        .filter(|&(&a, &b)| a == 0 && b == 0)
                        .count();
            let n1 = st[1].ins.iter().zip(st[1].out.iter())
                        .filter(|&(&a, &b)| a == 0 && b == 0)
                        .count();

            if n0 != n1 {
                continue 'candidates;
            }

            // Add mapping nx <-> mx to the state
            for j in graph_indices.clone() {
                st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
            }

            // Recurse
            match try_match(st, g0, g1) {
                None => {}
                result => return result,
            }

            // Restore state.
            for j in graph_indices.clone() {
                st[j].pop_mapping(nodes[j], g[j]);
            }
        }
        None
    }
    let mut st = [Vf2State::new(g0.node_count()),
                  Vf2State::new(g1.node_count())];
    try_match(&mut st, g0, g1).unwrap_or(false)
}

<|endoftext|>


<commit_before>use super::*;
use std::fs::File;
use std::io::{Read, Write};
use test;

#[test]
#[cfg(target_os = "linux")]
fn get_legacy_cargo_make_home_linux() {
    let mut home = env::var("HOME").unwrap();
    home.push_str("/.cargo-make");
    let cargo_make_home = get_legacy_cargo_make_home().unwrap();

    assert_eq!(home, cargo_make_home.to_str().unwrap());
}

#[test]
fn get_cargo_make_home_no_env() {
    env::remove_var("CARGO_MAKE_HOME");

    let cargo_make_home = get_legacy_cargo_make_home().unwrap();
    let home = get_cargo_make_home().unwrap();
    assert_eq!(home, cargo_make_home);
}

#[test]
fn get_cargo_make_home_with_env() {
    let path = env::current_dir().unwrap();
    let directory = path.join("examples/cargo-make");
    env::set_var("CARGO_MAKE_HOME", directory.to_str().unwrap());

    let home = get_cargo_make_home().unwrap();
    assert_eq!(home, directory);
}

#[test]
fn migrate_from_directory_not_exists() {
    let path = env::current_dir().unwrap();
    let legacy_directory = path.join("legacy_bad");
    let target_directory = path.join("target_bad");

    let done = migrate_from_directory(target_directory, "test.txt", &legacy_directory);

    assert!(done);
}

#[test]
fn migrate_from_directory_dir_exists_file_not_exists() {
    let path = env::current_dir().unwrap();
    let target_directory = path.join("target_bad");

    let legacy_directory = test::get_temp_test_directory();

    let done = migrate_from_directory(target_directory, "test.txt", &legacy_directory);

    assert!(done);
}

#[test]
fn migrate_from_directory_delete_legacy_directory() {
    let test_directory = test::get_temp_test_directory();
    let legacy_directory = test_directory.join("legacy");
    let target_directory = test_directory.join("target");
    create_dir_all(&legacy_directory).unwrap();

    let legacy_file = legacy_directory.join("test.txt");
    let mut legacy_file_pt = File::create(&legacy_file).unwrap();
    legacy_file_pt.write_all("test 123".as_bytes()).unwrap();

    let done = migrate_from_directory(target_directory.clone(), "test.txt", &legacy_directory);

    assert!(done);

    assert!(target_directory.exists());
    assert!(!legacy_directory.exists());

    let target_file = target_directory.join("test.txt");
    let mut target_file_pt = File::open(&target_file).unwrap();
    let mut file_text = String::new();
    target_file_pt.read_to_string(&mut file_text).unwrap();

    assert_eq!(&file_text, "test 123");
}
<commit_msg>fix test for windows<commit_after>use super::*;
use std::fs::File;
use std::io::{Read, Write};
use test;

#[test]
#[cfg(target_os = "linux")]
fn get_legacy_cargo_make_home_linux() {
    let mut home = env::var("HOME").unwrap();
    home.push_str("/.cargo-make");
    let cargo_make_home = get_legacy_cargo_make_home().unwrap();

    assert_eq!(home, cargo_make_home.to_str().unwrap());
}

#[test]
fn get_cargo_make_home_no_env() {
    env::remove_var("CARGO_MAKE_HOME");

    let cargo_make_home = get_legacy_cargo_make_home().unwrap();
    let home = get_cargo_make_home().unwrap();
    assert_eq!(home, cargo_make_home);
}

#[test]
fn get_cargo_make_home_with_env() {
    let path = env::current_dir().unwrap();
    let directory = path.join("examples/cargo-make");
    env::set_var("CARGO_MAKE_HOME", directory.to_str().unwrap());

    let home = get_cargo_make_home().unwrap();
    assert_eq!(home, directory);
}

#[test]
fn migrate_from_directory_not_exists() {
    let path = env::current_dir().unwrap();
    let legacy_directory = path.join("legacy_bad");
    let target_directory = path.join("target_bad");

    let done = migrate_from_directory(target_directory, "test.txt", &legacy_directory);

    assert!(done);
}

#[test]
fn migrate_from_directory_dir_exists_file_not_exists() {
    let path = env::current_dir().unwrap();
    let target_directory = path.join("target_bad");

    let legacy_directory = test::get_temp_test_directory();

    let done = migrate_from_directory(target_directory, "test.txt", &legacy_directory);

    assert!(done);
}

#[test]
fn migrate_from_directory_delete_legacy_directory() {
    let test_directory = test::get_temp_test_directory();
    let legacy_directory = test_directory.join("legacy");
    let target_directory = test_directory.join("target");
    create_dir_all(&legacy_directory).unwrap();

    let legacy_file = legacy_directory.join("test.txt");
    let mut legacy_file_pt = File::create(&legacy_file).unwrap();
    legacy_file_pt.write_all("test 123".as_bytes()).unwrap();

    let done = migrate_from_directory(target_directory.clone(), "test.txt", &legacy_directory);

    assert!(done);

    assert!(target_directory.exists());

    #[cfg(target_os = "linux")]
    assert!(!legacy_directory.exists());

    let target_file = target_directory.join("test.txt");
    let mut target_file_pt = File::open(&target_file).unwrap();
    let mut file_text = String::new();
    target_file_pt.read_to_string(&mut file_text).unwrap();

    assert_eq!(&file_text, "test 123");
}
<|endoftext|>


<commit_before>// Rust JSON serialization library
// Copyright (c) 2011 Google Inc.

import float;
import map;
import core::option;
import option::{some, none};
import str;
import vec;

export json;
export to_str;
export from_str;

export num;
export string;
export boolean;
export list;
export dict;

/*
Tag: json

Represents a json value.
*/
tag json {
    /* Variant: num */
    num(float);
    /* Variant: string */
    string(str);
    /* Variant: boolean */
    boolean(bool);
    /* Variant: list */
    list(@[json]);
    /* Variant: dict */
    dict(map::hashmap<str,json>);
    /* Variant: null */
    null;
}

/*
Function: to_str

Serializes a json value into a string.
*/
fn to_str(j: json) -> str {
    alt j {
        num(f) { float::to_str(f, 6u) }
        string(s) { #fmt["\"%s\"", s] } // XXX: escape
        boolean(true) { "true" }
        boolean(false) { "false" }
        list(@js) {
            str::concat(["[",
                    str::connect(
                        vec::map::<json,str>(js, { |e| to_str(e) }),
                        ", "),
                    "]"])
        }
        dict(m) {
            let parts = [];
            m.items({ |k, v|
                        vec::grow(parts, 1u,
                                  str::concat(["\"", k, "\": ", to_str(v)])
                        )
            });
            str::concat(["{ ", str::connect(parts, ", "), " }"])
        }
    }
}

fn rest(s: str) -> str {
    assert(str::char_len(s) >= 1u);
    str::char_slice(s, 1u, str::char_len(s))
}

fn from_str_str(s: str) -> (option::t<json>, str) {
    let pos = 0u;
    let len = str::byte_len(s);
    let escape = false;
    let res = "";

    alt str::char_at(s, 0u) {
        '"' { pos = 1u; }
        _ { ret (none, s); }
    }

    while (pos < len) {
        let chr = str::char_range_at(s, pos);
        let c = chr.ch;
        pos = chr.next;
        if (escape) {
            res = res + str::from_char(c);
            escape = false;
            cont;
        }
        if (c == '\\') {
            escape = true;
            cont;
        } else if (c == '"') {
            ret (some(string(res)),
                 str::char_slice(s, pos, str::char_len(s)));
        }
        res = res + str::from_char(c);
    }

    ret (none, s);
}

fn from_str_list(s: str) -> (option::t<json>, str) {
    if str::char_at(s, 0u) != '[' { ret (none, s); }
    let s0 = str::trim_left(rest(s));
    let vals = [];
    if str::is_empty(s0) { ret (none, s0); }
    if str::char_at(s0, 0u) == ']' { ret (some(list(@[])), rest(s0)); }
    while str::is_not_empty(s0) {
        s0 = str::trim_left(s0);
        let (next, s1) = from_str_helper(s0);
        s0 = s1;
        alt next {
            some(j) { vec::grow(vals, 1u, j); }
            none { ret (none, s0); }
        }
        s0 = str::trim_left(s0);
        if str::is_empty(s0) { ret (none, s0); }
        alt str::char_at(s0, 0u) {
            ',' { }
            ']' { ret (some(list(@vals)), rest(s0)); }
            _ { ret (none, s0); }
        }
        s0 = rest(s0);
    }
    ret (none, s0);
}

fn from_str_dict(s: str) -> (option::t<json>, str) {
    if str::char_at(s, 0u) != '{' { ret (none, s); }
    let s0 = str::trim_left(rest(s));
    let vals = map::new_str_hash::<json>();
    if str::is_empty(s0) { ret (none, s0); }
    if str::char_at(s0, 0u) == '}' { ret (some(dict(vals)), rest(s0)); }
    while str::is_not_empty(s0) {
        s0 = str::trim_left(s0);
        let (next, s1) = from_str_helper(s0);    // key
        let key = "";
        s0 = s1;
        alt next {
            some(string(k)) { key = k; }
            _ { ret (none, s0); }
        }
        s0 = str::trim_left(s0);
        if str::is_empty(s0) { ret (none, s0); }
        if str::char_at(s0, 0u) != ':' { ret (none, s0); }
        s0 = str::trim_left(rest(s0));
        let (next, s1) = from_str_helper(s0);    // value
        s0 = s1;
        alt next {
            some(j) { vals.insert(key, j); }
            _ { ret (none, s0); }
        }
        s0 = str::trim_left(s0);
        if str::is_empty(s0) { ret (none, s0); }
        alt str::char_at(s0, 0u) {
            ',' { }
            '}' { ret (some(dict(vals)), rest(s0)); }
            _ { ret (none, s0); }
        }
        s0 = str::trim_left(rest(s0));
    }
    (none, s)
}

fn from_str_float(s: str) -> (option::t<json>, str) {
    let pos = 0u;
    let len = str::byte_len(s);
    let res = 0f;
    let neg = 1f;

    alt str::char_at(s, 0u) {
        '-' {
            neg = -1f;
            pos = 1u;
        }
        '+' {
            pos = 1u;
        }
        '0' to '9' | '.' { }
        _ { ret (none, s); }
    }

    while (pos < len) {
        let opos = pos;
        let chr = str::char_range_at(s, pos);
        let c = chr.ch;
        pos = chr.next;
        alt c {
            '0' to '9' {
                res = res * 10f;
                res += ((c as int) - ('0' as int)) as float;
            }
            '.' { break; }
            _ { ret (some(num(neg * res)),
                     str::char_slice(s, opos, str::char_len(s))); }
        }
    }

    if pos == len {
        ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s)));
    }

    let dec = 1f;
    while (pos < len) {
        let opos = pos;
        let chr = str::char_range_at(s, pos);
        let c = chr.ch;
        pos = chr.next;
        alt c {
            '0' to '9' {
                dec /= 10f;
                res += (((c as int) - ('0' as int)) as float) * dec;
            }
            _ { ret (some(num(neg * res)),
                     str::char_slice(s, opos, str::char_len(s))); }
        }
    }
    ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s)));
}

fn from_str_bool(s: str) -> (option::t<json>, str) {
    if (str::starts_with(s, "true")) {
        (some(boolean(true)), str::slice(s, 4u, str::byte_len(s)))
    } else if (str::starts_with(s, "false")) {
        (some(boolean(false)), str::slice(s, 5u, str::byte_len(s)))
    } else {
        (none, s)
    }
}

fn from_str_null(s: str) -> (option::t<json>, str) {
    if (str::starts_with(s, "null")) {
        (some(null), str::slice(s, 4u, str::byte_len(s)))
    } else {
        (none, s)
    }
}

fn from_str_helper(s: str) -> (option::t<json>, str) {
    let s = str::trim_left(s);
    if str::is_empty(s) { ret (none, s); }
    let start = str::char_at(s, 0u);
    alt start {
        '"' { from_str_str(s) }
        '[' { from_str_list(s) }
        '{' { from_str_dict(s) }
        '0' to '9' | '-' | '+' | '.' { from_str_float(s) }
        't' | 'f' { from_str_bool(s) }
        'n' { from_str_null(s) }
        _ { ret (none, s); }
    }
}

/*
Function: from_str

Deserializes a json value from a string.
*/
fn from_str(s: str) -> option::t<json> {
    let (j, _) = from_str_helper(s);
    j
}
<commit_msg>json: to_str() also for "null"<commit_after>// Rust JSON serialization library
// Copyright (c) 2011 Google Inc.

import float;
import map;
import core::option;
import option::{some, none};
import str;
import vec;

export json;
export to_str;
export from_str;

export num;
export string;
export boolean;
export list;
export dict;

/*
Tag: json

Represents a json value.
*/
tag json {
    /* Variant: num */
    num(float);
    /* Variant: string */
    string(str);
    /* Variant: boolean */
    boolean(bool);
    /* Variant: list */
    list(@[json]);
    /* Variant: dict */
    dict(map::hashmap<str,json>);
    /* Variant: null */
    null;
}

/*
Function: to_str

Serializes a json value into a string.
*/
fn to_str(j: json) -> str {
    alt j {
        num(f) { float::to_str(f, 6u) }
        string(s) { #fmt["\"%s\"", s] } // XXX: escape
        boolean(true) { "true" }
        boolean(false) { "false" }
        list(@js) {
            str::concat(["[",
                    str::connect(
                        vec::map::<json,str>(js, { |e| to_str(e) }),
                        ", "),
                    "]"])
        }
        dict(m) {
            let parts = [];
            m.items({ |k, v|
                        vec::grow(parts, 1u,
                                  str::concat(["\"", k, "\": ", to_str(v)])
                        )
            });
            str::concat(["{ ", str::connect(parts, ", "), " }"])
        }
        null { "null" }
    }
}

fn rest(s: str) -> str {
    assert(str::char_len(s) >= 1u);
    str::char_slice(s, 1u, str::char_len(s))
}

fn from_str_str(s: str) -> (option::t<json>, str) {
    let pos = 0u;
    let len = str::byte_len(s);
    let escape = false;
    let res = "";

    alt str::char_at(s, 0u) {
        '"' { pos = 1u; }
        _ { ret (none, s); }
    }

    while (pos < len) {
        let chr = str::char_range_at(s, pos);
        let c = chr.ch;
        pos = chr.next;
        if (escape) {
            res = res + str::from_char(c);
            escape = false;
            cont;
        }
        if (c == '\\') {
            escape = true;
            cont;
        } else if (c == '"') {
            ret (some(string(res)),
                 str::char_slice(s, pos, str::char_len(s)));
        }
        res = res + str::from_char(c);
    }

    ret (none, s);
}

fn from_str_list(s: str) -> (option::t<json>, str) {
    if str::char_at(s, 0u) != '[' { ret (none, s); }
    let s0 = str::trim_left(rest(s));
    let vals = [];
    if str::is_empty(s0) { ret (none, s0); }
    if str::char_at(s0, 0u) == ']' { ret (some(list(@[])), rest(s0)); }
    while str::is_not_empty(s0) {
        s0 = str::trim_left(s0);
        let (next, s1) = from_str_helper(s0);
        s0 = s1;
        alt next {
            some(j) { vec::grow(vals, 1u, j); }
            none { ret (none, s0); }
        }
        s0 = str::trim_left(s0);
        if str::is_empty(s0) { ret (none, s0); }
        alt str::char_at(s0, 0u) {
            ',' { }
            ']' { ret (some(list(@vals)), rest(s0)); }
            _ { ret (none, s0); }
        }
        s0 = rest(s0);
    }
    ret (none, s0);
}

fn from_str_dict(s: str) -> (option::t<json>, str) {
    if str::char_at(s, 0u) != '{' { ret (none, s); }
    let s0 = str::trim_left(rest(s));
    let vals = map::new_str_hash::<json>();
    if str::is_empty(s0) { ret (none, s0); }
    if str::char_at(s0, 0u) == '}' { ret (some(dict(vals)), rest(s0)); }
    while str::is_not_empty(s0) {
        s0 = str::trim_left(s0);
        let (next, s1) = from_str_helper(s0);    // key
        let key = "";
        s0 = s1;
        alt next {
            some(string(k)) { key = k; }
            _ { ret (none, s0); }
        }
        s0 = str::trim_left(s0);
        if str::is_empty(s0) { ret (none, s0); }
        if str::char_at(s0, 0u) != ':' { ret (none, s0); }
        s0 = str::trim_left(rest(s0));
        let (next, s1) = from_str_helper(s0);    // value
        s0 = s1;
        alt next {
            some(j) { vals.insert(key, j); }
            _ { ret (none, s0); }
        }
        s0 = str::trim_left(s0);
        if str::is_empty(s0) { ret (none, s0); }
        alt str::char_at(s0, 0u) {
            ',' { }
            '}' { ret (some(dict(vals)), rest(s0)); }
            _ { ret (none, s0); }
        }
        s0 = str::trim_left(rest(s0));
    }
    (none, s)
}

fn from_str_float(s: str) -> (option::t<json>, str) {
    let pos = 0u;
    let len = str::byte_len(s);
    let res = 0f;
    let neg = 1f;

    alt str::char_at(s, 0u) {
        '-' {
            neg = -1f;
            pos = 1u;
        }
        '+' {
            pos = 1u;
        }
        '0' to '9' | '.' { }
        _ { ret (none, s); }
    }

    while (pos < len) {
        let opos = pos;
        let chr = str::char_range_at(s, pos);
        let c = chr.ch;
        pos = chr.next;
        alt c {
            '0' to '9' {
                res = res * 10f;
                res += ((c as int) - ('0' as int)) as float;
            }
            '.' { break; }
            _ { ret (some(num(neg * res)),
                     str::char_slice(s, opos, str::char_len(s))); }
        }
    }

    if pos == len {
        ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s)));
    }

    let dec = 1f;
    while (pos < len) {
        let opos = pos;
        let chr = str::char_range_at(s, pos);
        let c = chr.ch;
        pos = chr.next;
        alt c {
            '0' to '9' {
                dec /= 10f;
                res += (((c as int) - ('0' as int)) as float) * dec;
            }
            _ { ret (some(num(neg * res)),
                     str::char_slice(s, opos, str::char_len(s))); }
        }
    }
    ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s)));
}

fn from_str_bool(s: str) -> (option::t<json>, str) {
    if (str::starts_with(s, "true")) {
        (some(boolean(true)), str::slice(s, 4u, str::byte_len(s)))
    } else if (str::starts_with(s, "false")) {
        (some(boolean(false)), str::slice(s, 5u, str::byte_len(s)))
    } else {
        (none, s)
    }
}

fn from_str_null(s: str) -> (option::t<json>, str) {
    if (str::starts_with(s, "null")) {
        (some(null), str::slice(s, 4u, str::byte_len(s)))
    } else {
        (none, s)
    }
}

fn from_str_helper(s: str) -> (option::t<json>, str) {
    let s = str::trim_left(s);
    if str::is_empty(s) { ret (none, s); }
    let start = str::char_at(s, 0u);
    alt start {
        '"' { from_str_str(s) }
        '[' { from_str_list(s) }
        '{' { from_str_dict(s) }
        '0' to '9' | '-' | '+' | '.' { from_str_float(s) }
        't' | 'f' { from_str_bool(s) }
        'n' { from_str_null(s) }
        _ { ret (none, s); }
    }
}

/*
Function: from_str

Deserializes a json value from a string.
*/
fn from_str(s: str) -> option::t<json> {
    let (j, _) = from_str_helper(s);
    j
}
<|endoftext|>


<commit_before>//! Support code for rustc's built in unit-test and micro-benchmarking
//! framework.
//!
//! Almost all user code will only be interested in `Bencher` and
//! `black_box`. All other interactions (such as writing tests and
//! benchmarks themselves) should be done via the `#[test]` and
//! `#[bench]` attributes.
//!
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.

#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       test(attr(deny(warnings))))]
#![feature(staged_api)]
#![feature(test)]

extern crate libtest;
pub use libtest::*;
<commit_msg>Move black_box back to rust-lang/libtest and use explicit imports<commit_after>//! Support code for rustc's built in unit-test and micro-benchmarking
//! framework.
//!
//! Almost all user code will only be interested in `Bencher` and
//! `black_box`. All other interactions (such as writing tests and
//! benchmarks themselves) should be done via the `#[test]` and
//! `#[bench]` attributes.
//!
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.

#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       test(attr(deny(warnings))))]
#![feature(asm)]
#![feature(staged_api)]
#![feature(test)]

extern crate libtest;
pub use libtest::{test_main_static, TestDescAndFn, StaticTestFn, StaticBenchFn, Options};

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))]
pub fn black_box<T>(dummy: T) -> T {
    // we need to "use" the argument in some way LLVM can't
    // introspect.
    unsafe { asm!("" : : "r"(&dummy)) }
    dummy
}
#[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))]
#[inline(never)]
pub fn black_box<T>(dummy: T) -> T {
    dummy
}
<|endoftext|>


<commit_before>extern crate regex;
use self::regex::Regex;

pub struct LsbRelease {
    pub distro: Option<String>,
    pub version: Option<String>
}

pub fn parse(file: String) -> LsbRelease {
    let distrib_regex = Regex::new(r"DISTRIB_ID=(\w+)").unwrap();
    let distrib_release_regex = Regex::new(r"DISTRIB_RELEASE=([\w\.]+)").unwrap();

    let distro = match distrib_regex.captures_iter(&file).next() {
        Some(m) => {
            match m.at(1) {
                Some(distro) => {
                    Some(distro.to_string())
                },
                None => None
            }
        },
        None => None
    };

    let version = match distrib_release_regex.captures_iter(&file).next() {
        Some(m) => {
            match m.at(1) {
                Some(version) => Some(version.to_string()),
                None => None
            }
        },
        None => None
    };

    LsbRelease {
        distro: distro,
        version: version
    }
}
<commit_msg>add from_file function to lsb_release<commit_after>extern crate regex;
use self::regex::Regex;
use std::io::prelude::*;
use std::fs::File;
use std::convert::AsRef;
use std::path::Path;
use std::io::Error;

pub struct LsbRelease {
    pub distro: Option<String>,
    pub version: Option<String>
}

pub fn from_file<P: AsRef<Path>>(path: P) -> Result<LsbRelease, Error> {
    let mut handle = match File::open(path) {
        Ok(h) => h,
        Err(err) => return Err(err)
    };

    let mut file_content = String::new();

    handle.read_to_string(&mut file_content);
    let release = parse(file_content);
    Ok(release)
}

pub fn parse(file: String) -> LsbRelease {
    let distrib_regex = Regex::new(r"DISTRIB_ID=(\w+)").unwrap();
    let distrib_release_regex = Regex::new(r"DISTRIB_RELEASE=([\w\.]+)").unwrap();

    let distro = match distrib_regex.captures_iter(&file).next() {
        Some(m) => {
            match m.at(1) {
                Some(distro) => {
                    Some(distro.to_string())
                },
                None => None
            }
        },
        None => None
    };

    let version = match distrib_release_regex.captures_iter(&file).next() {
        Some(m) => {
            match m.at(1) {
                Some(version) => Some(version.to_string()),
                None => None
            }
        },
        None => None
    };

    LsbRelease {
        distro: distro,
        version: version
    }
}
<|endoftext|>


<commit_before>/* cpu.rs - Exposes all of the implementation needed to organize and execute VR4300i opcodes. */

/*

CPU0

  00h = r0/reg0     08h = t0/reg8     10h = s0/reg16    18h = t8/reg24
  01h = at/reg1     09h = t1/reg9     11h = s1/reg17    19h = t9/reg25
  02h = v0/reg2     0Ah = t2/reg10    12h = s2/reg18    1Ah = k0/reg26
  03h = v1/reg3     0Bh = t3/reg11    13h = s3/reg19    1Bh = k1/reg27
  04h = a0/reg4     0Ch = t4/reg12    14h = s4/reg20    1Ch = gp/reg28
  05h = a1/reg5     0Dh = t5/reg13    15h = s5/reg21    1Dh = sp/reg29
  06h = a2/reg6     0Eh = t6/reg14    16h = s6/reg22    1Eh = s8/reg30
  07h = a3/reg7     0Fh = t7/reg15    17h = s7/reg23    1Fh = ra/reg31

*/

const GPR_NAMES: [&'static str; GPR_SIZE] = [
    "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
    "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
];

use std::fmt;

use n64::MC;

mod op;
use self::op::*;

mod instruction;
use self::instruction::Inst;

mod cp0;
use self::cp0::*;

mod cp1;
use self::cp1::*;

/* Size of the general purpose register file. */
const GPR_SIZE: usize = 32;

pub struct CPU {
    /* mmu / tlb co-processor */
    pub cp0: CP0,
    /* floating point co-processor */
    pub cp1: CP1,

    pub gpr: [u64; GPR_SIZE],

    pub hi: u64,
    pub lo: u64,
    pub ll: u8,
    pub pc: u64,

    /* last executed instruction for debugging */
    pub last: u32
}

impl CPU {

    pub fn new(pc: u64) -> CPU {
        CPU {
            cp0: CP0::new(),
            cp1: CP1::new(),

            gpr: [0; GPR_SIZE],

            hi: 0,
            lo: 0,
            ll: 0,
            pc: pc,

            last: 0
        }
    }

    fn rgpr(&self, reg: usize) -> u64 {
        self.gpr[reg]
    }

    fn wgpr(&mut self, val: u64, reg: usize) {
        match reg {
            0 => {

            }, _ => {
                self.gpr[reg] = val;
            },
        }
    }

    /* Handlers for the 3 instruction formats. - Chapter 3.1 in NEC VR4300 manual. */

    fn exec_imm(&mut self, i: Inst) {
        let rs = self.rgpr(i.rs());
        let imm = i.imm();
        let rt = i.function()(0, rs, imm);
        self.wgpr(rt, i.rt());
    }

    fn exec_ldst(&mut self, i: Inst, mc: &mut MC) {
        let base = self.rgpr(i.rs()) as i64;
        let offset = i.offset() as i16 as i64;

        match i.class() {
            OpC::L => {
                let val = mc.read((base + offset) as u32) as u64;
                let rt = i.function()(val, 0, 0);
                self.wgpr(rt, i.rt());
            },
            OpC::S => {
                let rt = self.rgpr(i.rt());
                let val = i.function()(rt, 0, 0) as u32;
                mc.write((base + offset) as u32, val);
            }, _ => {

            }
        }
    }

    fn exec_jump(&mut self, i: Inst) {

        match i.op() {

            Op::J => {
                let target = i.target();
                /* sub 4 here because we will inc the pc by 4 later */
                self.pc = target - 4;
            }, Op::Jal => {
                let target = i.target();
                let pc = self.pc;
                self.wgpr(pc, 31);
                /* sub 4 here because we will inc the pc by 4 later */
                self.pc = target - 4;
            }, Op::Jr => {
                let target = self.rgpr(i.rs());
                /* sub 4 here because we will inc the pc by 4 later */
                self.pc = target - 4;
            }, Op::Jalr => {
                let target = self.rgpr(i.rs());
                let pc = self.pc;
                self.wgpr(pc, i.rd());
                /* sub 4 here because we will inc the pc by 4 later */
                self.pc = target - 4;
            }, _ => {

            }

        }
    }

    fn exec_branch(&mut self, i: Inst) {
        let rs = self.rgpr(i.rs());
        let rt = self.rgpr(i.rt());
        let offset = ((i.offset() as i16 as i32) << 2) as i64;

        let should_branch = i.function()(rt, rs, 0);
        if should_branch > 0 {
            self.pc = (self.pc as i64 + offset) as u64;
        }
    }

    /* Handler for the register (R-Type) instructions. */
    fn exec_reg(&mut self, i: Inst) {
        let rs = self.rgpr(i.rs());
        let rt = self.rgpr(i.rt());
        let rd = i.function()(rt, rs, i.sa());
        self.wgpr(rd, i.rd())
    }

    pub fn exec(&mut self, i: Inst, mc: &mut MC) {

        match i.class() {
            OpC::I => {
                self.exec_imm(i);
            }, OpC::L | OpC::S => {
                self.exec_ldst(i, mc);
            }, OpC::J => {
                self.exec_jump(i);
            }, OpC::B => {
                self.exec_branch(i);
            }, OpC::R => {
                self.exec_reg(i);
            } _ => {
                panic!("Invalid instruction class {:#x}", i.class() as u32);
            }
        }

    }

    pub fn cycle(&mut self, mc: &mut MC) {

        let op = mc.read(self.pc as u32);

        let i = Inst(op);

        /* quick way to store the last instruction */
        self.last = op;

        println!("{:#x}: ({:#x}) {}", self.pc, i.0, i);

        match i.kind() {
            Op::Cop0 => {
                self.cp0.exec(i);
            }, Op::Cop1 => {
                self.cp1.exec(i);
            }, Op::Cop2 => {
                panic!("Attempt to perfrom a coprocessor instruction on an invalid coprocessor.");
            }, Op::Reserved => {
                panic!("Attempt made to execute a reserved instruction {:#x}.", i.opcode());
            }, _ => {
                self.exec(i, mc);
            }
        };

        self.pc += 4;

    }
}

pub fn print_last(cpu: &CPU) {

    let i = Inst(cpu.last);

    println!("{}", i);
    println!("{:02} ({}): {:#018X} ", i.rd(), GPR_NAMES[i.rd()], cpu.rgpr(i.rd()));
    println!("{:02} ({}): {:#018X} ", i.rt(), GPR_NAMES[i.rt()], cpu.rgpr(i.rt()));
    println!("{:02} ({}): {:#018X} ", i.rs(), GPR_NAMES[i.rs()], cpu.rgpr(i.rs()));
}

use self::cp0::CP0_NAMES;

impl fmt::Debug for CPU {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        const REGS_PER_LINE: usize = 2;

        for r in 0..GPR_SIZE {
            if (r % REGS_PER_LINE) == 0 {
                try!(writeln!(f, ""))
            }

            try!(write!(f, "{:02} ({}): {:#018X} ", r, GPR_NAMES[r], self.rgpr(r)))
        }

        try!(writeln!(f, ""));

        for r in 0..GPR_SIZE {
            if (r % REGS_PER_LINE) == 0 {
                try!(writeln!(f, ""))
            }

            try!(write!(f, "{:02} ({:8}): {:#018X} ", r, cp0::CP0_NAMES[r], self.cp0.rgpr(r)))
        }

        try!(write!(f, "\n\nCPU Floating Point Registers:"));

        // for r in 0..GPR_SIZE {
        //     if (r % REGS_PER_LINE) == 0 {
        //         try!(writeln!(f, ""))
        //     }
        //
        //     try!(write!(f, "fpr{:02}: {:21} ", r, self.rfpr(r)))
        // }

        Ok(())

    }
}
<commit_msg>move instructions into exec<commit_after>/* cpu.rs - Exposes all of the implementation needed to organize and execute VR4300i opcodes. */

/*

CPU0

  00h = r0/reg0     08h = t0/reg8     10h = s0/reg16    18h = t8/reg24
  01h = at/reg1     09h = t1/reg9     11h = s1/reg17    19h = t9/reg25
  02h = v0/reg2     0Ah = t2/reg10    12h = s2/reg18    1Ah = k0/reg26
  03h = v1/reg3     0Bh = t3/reg11    13h = s3/reg19    1Bh = k1/reg27
  04h = a0/reg4     0Ch = t4/reg12    14h = s4/reg20    1Ch = gp/reg28
  05h = a1/reg5     0Dh = t5/reg13    15h = s5/reg21    1Dh = sp/reg29
  06h = a2/reg6     0Eh = t6/reg14    16h = s6/reg22    1Eh = s8/reg30
  07h = a3/reg7     0Fh = t7/reg15    17h = s7/reg23    1Fh = ra/reg31

*/

const GPR_NAMES: [&'static str; GPR_SIZE] = [
    "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
    "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
];

use std::fmt;

use n64::MC;

mod op;
use self::op::*;

mod instruction;
use self::instruction::Inst;

mod cp0;
use self::cp0::*;

mod cp1;
use self::cp1::*;

/* Size of the general purpose register file. */
const GPR_SIZE: usize = 32;

pub struct CPU {
    /* mmu / tlb co-processor */
    pub cp0: CP0,
    /* floating point co-processor */
    pub cp1: CP1,

    pub gpr: [u64; GPR_SIZE],

    pub hi: u64,
    pub lo: u64,
    pub ll: u8,
    pub pc: u64,

    /* last executed instruction for debugging */
    pub last: u32
}

impl CPU {

    pub fn new(pc: u64) -> CPU {
        CPU {
            cp0: CP0::new(),
            cp1: CP1::new(),

            gpr: [0; GPR_SIZE],

            hi: 0,
            lo: 0,
            ll: 0,
            pc: pc,

            last: 0
        }
    }

    fn rgpr(&self, reg: usize) -> u64 {
        self.gpr[reg]
    }

    fn wgpr(&mut self, val: u64, reg: usize) {
        match reg {
            0 => {

            }, _ => {
                self.gpr[reg] = val;
            },
        }
    }

    pub fn exec(&mut self, i: Inst, mc: &mut MC) {

        match i.class() {
            OpC::I => {

                let rs = self.rgpr(i.rs());
                let imm = i.imm();
                let rt = i.function()(0, rs, imm);
                self.wgpr(rt, i.rt());

            }, OpC::L => {

                let base = self.rgpr(i.rs()) as i64;
                let offset = i.offset() as i16 as i64;
                let val = mc.read((base + offset) as u32) as u64;
                let rt = i.function()(val, 0, 0);
                self.wgpr(rt, i.rt());

            }, OpC::S => {

                let base = self.rgpr(i.rs()) as i64;
                let offset = i.offset() as i16 as i64;
                let rt = self.rgpr(i.rt());
                let val = i.function()(rt, 0, 0) as u32;
                mc.write((base + offset) as u32, val);

            }, OpC::J => {

                match i.op() {

                    Op::J => {
                        let target = i.target();
                        /* sub 4 here because we will inc the pc by 4 later */
                        self.pc = target - 4;
                    }, Op::Jal => {
                        let target = i.target();
                        let pc = self.pc;
                        self.wgpr(pc, 31);
                        /* sub 4 here because we will inc the pc by 4 later */
                        self.pc = target - 4;
                    }, Op::Jr => {
                        let target = self.rgpr(i.rs());
                        /* sub 4 here because we will inc the pc by 4 later */
                        self.pc = target - 4;
                    }, Op::Jalr => {
                        let target = self.rgpr(i.rs());
                        let pc = self.pc;
                        self.wgpr(pc, i.rd());
                        /* sub 4 here because we will inc the pc by 4 later */
                        self.pc = target - 4;
                    }, _ => {

                    }

                }

            }, OpC::B => {

                let rs = self.rgpr(i.rs());
                let rt = self.rgpr(i.rt());
                let offset = ((i.offset() as i16 as i32) << 2) as i64;

                let should_branch = i.function()(rt, rs, 0);
                if should_branch > 0 {
                    self.pc = (self.pc as i64 + offset) as u64;
                }

            }, OpC::R => {

                let rs = self.rgpr(i.rs());
                let rt = self.rgpr(i.rt());
                let rd = i.function()(rt, rs, i.sa());
                self.wgpr(rd, i.rd())

            } _ => {
                panic!("Invalid instruction class {:#x}", i.class() as u32);
            }
        }

    }

    pub fn cycle(&mut self, mc: &mut MC) {

        let op = mc.read(self.pc as u32);

        let i = Inst(op);

        /* quick way to store the last instruction */
        self.last = op;

        println!("{:#x}: ({:#x}) {}", self.pc, i.0, i);

        match i.kind() {
            Op::Cop0 => {
                self.cp0.exec(i);
            }, Op::Cop1 => {
                self.cp1.exec(i);
            }, Op::Cop2 => {
                panic!("Attempt to perfrom a coprocessor instruction on an invalid coprocessor.");
            }, Op::Reserved => {
                panic!("Attempt made to execute a reserved instruction {:#x}.", i.opcode());
            }, _ => {
                self.exec(i, mc);
            }
        };

        self.pc += 4;

    }
}

pub fn print_last(cpu: &CPU) {

    let i = Inst(cpu.last);

    println!("{}", i);
    println!("{:02} ({}): {:#018X} ", i.rd(), GPR_NAMES[i.rd()], cpu.rgpr(i.rd()));
    println!("{:02} ({}): {:#018X} ", i.rt(), GPR_NAMES[i.rt()], cpu.rgpr(i.rt()));
    println!("{:02} ({}): {:#018X} ", i.rs(), GPR_NAMES[i.rs()], cpu.rgpr(i.rs()));
}

use self::cp0::CP0_NAMES;

impl fmt::Debug for CPU {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        const REGS_PER_LINE: usize = 2;

        for r in 0..GPR_SIZE {
            if (r % REGS_PER_LINE) == 0 {
                try!(writeln!(f, ""))
            }

            try!(write!(f, "{:02} ({}): {:#018X} ", r, GPR_NAMES[r], self.rgpr(r)))
        }

        try!(writeln!(f, ""));

        for r in 0..GPR_SIZE {
            if (r % REGS_PER_LINE) == 0 {
                try!(writeln!(f, ""))
            }

            try!(write!(f, "{:02} ({:8}): {:#018X} ", r, cp0::CP0_NAMES[r], self.cp0.rgpr(r)))
        }

        try!(write!(f, "\n\nCPU Floating Point Registers:"));

        // for r in 0..GPR_SIZE {
        //     if (r % REGS_PER_LINE) == 0 {
        //         try!(writeln!(f, ""))
        //     }
        //
        //     try!(write!(f, "fpr{:02}: {:21} ", r, self.rfpr(r)))
        // }

        Ok(())

    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2017 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! An implementation of the [Cap'n Proto remote procedure call](https://capnproto.org/rpc.html)
//! protocol. Includes all [Level 1](https://capnproto.org/rpc.html#protocol-features) features.
//!
//! # Example
//!
//! ```capnp
//! # Cap'n Proto schema
//! interface Foo {
//!     identity @0 (x: UInt32) -> (y: UInt32);
//! }
//! ```
//!
//! ```ignore
//! // Rust server defining an implementation of Foo.
//! struct FooImpl;
//! impl foo::Server for FooImpl {
//!     fn identity(&mut self,
//!                 params: foo::IdentityParams,
//!                 mut results: foo::IdentityResults)
//!                 -> Promise<(), ::capnp::Error>
//!     {
//!         let x = pry!(params.get()).get_x();
//!         results.get().set_y(x);
//!         Promise::ok(())
//!     }
//! }
//! ```
//!
//! ```ignore
//! // Rust client calling a remote implementation of Foo.
//! let mut request = foo_client.identity_request();
//! request.get().set_x(123);
//! let promise = request.send().promise.and_then(|response| {
//!     println!("results = {}", response.get()?.get_y());
//!     Ok(())
//! });
//! ```
//!
//! For a more complete example, see https://github.com/capnproto/capnproto-rust/tree/master/capnp-rpc/examples/calculator

use std::pin::Pin;
use std::task::{Context, Poll};
use futures::{Future, FutureExt, TryFutureExt};
use futures::channel::oneshot;
use capnp::Error;
use capnp::capability::Promise;
use capnp::private::capability::{ClientHook};
use std::cell::{RefCell};
use std::rc::{Rc};

use crate::task_set::TaskSet;
pub use crate::rpc::Disconnector;

/// Code generated from
/// [rpc.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc.capnp).
pub mod rpc_capnp;

/// Code generated from
/// [rpc-twoparty.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc-twoparty.capnp).
pub mod rpc_twoparty_capnp;

/// Like `try!()`, but for functions that return a `Promise<T, E>` rather than a `Result<T, E>`.
///
/// Unwraps a `Result<T, E>`. In the case of an error `Err(e)`, immediately returns from the
/// enclosing function with `Promise::err(e)`.
#[macro_export]
macro_rules! pry {
    ($expr:expr) => (
        match $expr {
            ::std::result::Result::Ok(val) => val,
            ::std::result::Result::Err(err) => {
                return ::capnp::capability::Promise::err(::std::convert::From::from(err))
            }
        })
}

mod broken;
mod local;
mod queued;
mod rpc;
mod attach;
mod sender_queue;
mod split;
mod task_set;
pub mod twoparty;

pub trait OutgoingMessage {
    fn get_body<'a>(&'a mut self) -> ::capnp::Result<::capnp::any_pointer::Builder<'a>>;
    fn get_body_as_reader<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;

    /// Sends the message. Returns a promise for the message that resolves once the send has completed.
    /// Dropping the returned promise does *not* cancel the send.
    fn send(self: Box<Self>)
            -> (Promise<Rc<::capnp::message::Builder<::capnp::message::HeapAllocator>>, ::capnp::Error>,
                Rc<::capnp::message::Builder<::capnp::message::HeapAllocator>>);

    fn take(self: Box<Self>) -> ::capnp::message::Builder<::capnp::message::HeapAllocator>;
}

pub trait IncomingMessage {
    fn get_body<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;
}

pub trait Connection<VatId> {
    fn get_peer_vat_id(&self) -> VatId;
    fn new_outgoing_message(&mut self, first_segment_word_size: u32) -> Box<dyn OutgoingMessage>;

    /// Waits for a message to be received and returns it.  If the read stream cleanly terminates,
    /// returns None. If any other problem occurs, returns an Error.
    fn receive_incoming_message(&mut self) -> Promise<Option<Box<dyn IncomingMessage>>, Error>;

    // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The
    // returned promise resolves after shutdown is complete.
    fn shutdown(&mut self, result: ::capnp::Result<()>) -> Promise<(), Error>;
}

pub trait VatNetwork<VatId> {
    /// Returns None if `hostId` refers to the local vat.
    fn connect(&mut self, host_id: VatId) -> Option<Box<dyn Connection<VatId>>>;

    /// Waits for the next incoming connection and return it.
    fn accept(&mut self) -> Promise<Box<dyn Connection<VatId>>, ::capnp::Error>;

    fn drive_until_shutdown(&mut self) -> Promise<(), Error>;
}

/// A portal to objects available on the network.
///
/// The RPC implemententation sits on top of an implementation of `VatNetwork`, which
/// determines how to form connections between vats. The RPC implementation determines
/// how to use such connections to manage object references and make method calls.
///
/// At the moment, this is all rather more general than it needs to be, because the only
/// implementation of `VatNetwork` is `twoparty::VatNetwork`. However, eventually we
/// will need to have more sophisticated `VatNetwork` implementations, in order to support
/// [level 3](https://capnproto.org/rpc.html#protocol-features) features.
///
/// An `RpcSystem` is a `Future` and needs to be driven by a task executor. A common way
/// accomplish that is to pass the `RpcSystem` to `tokio_core::reactor::Handle::spawn()`.
#[must_use = "futures do nothing unless polled"]
pub struct RpcSystem<VatId> where VatId: 'static {
    network: Box<dyn crate::VatNetwork<VatId>>,

    bootstrap_cap: Box<dyn ClientHook>,

    // XXX To handle three or more party networks, this should be a map from connection pointers
    // to connection states.
    connection_state: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,

    tasks: TaskSet<Error>,
    handle: crate::task_set::TaskSetHandle<Error>
}

impl <VatId> RpcSystem <VatId> {
    /// Constructs a new `RpcSystem` with the given network and bootstrap capability.
    pub fn new(
        mut network: Box<dyn crate::VatNetwork<VatId>>,
        bootstrap: Option<::capnp::capability::Client>) -> RpcSystem<VatId>
    {
        let bootstrap_cap = match bootstrap {
            Some(cap) => cap.hook,
            None => broken::new_cap(Error::failed("no bootstrap capability".to_string())),
        };
        let (mut handle, tasks) = TaskSet::new(Box::new(SystemTaskReaper));

        let mut handle1 = handle.clone();
        handle.add(network.drive_until_shutdown().then(move |r| {
            let r = match r {
                Ok(()) => Ok(()),
                Err(e) => {
                    if e.kind != ::capnp::ErrorKind::Disconnected {
                        // Don't report disconnects as an error.
                        Err(e)
                    } else {
                        Ok(())
                    }
                }
            };

            handle1.terminate(r);
            Promise::ok(())
        }));

        let mut result = RpcSystem {
            network: network,
            bootstrap_cap: bootstrap_cap,
            connection_state: Rc::new(RefCell::new(None)),

            tasks: tasks,
            handle: handle.clone(),
        };

        let accept_loop = result.accept_loop();
        handle.add(accept_loop);
        result
    }

    /// Connects to the given vat and returns its bootstrap interface.
    pub fn bootstrap<T>(&mut self, vat_id: VatId) -> T
        where T: ::capnp::capability::FromClientHook
    {
        let connection = match self.network.connect(vat_id) {
            Some(connection) => connection,
            None => {
                return T::new(self.bootstrap_cap.clone());
            }
        };
        let connection_state =
            RpcSystem::get_connection_state(self.connection_state.clone(),
                                            self.bootstrap_cap.clone(),
                                            connection, self.handle.clone());

        let hook = rpc::ConnectionState::bootstrap(connection_state.clone());
        T::new(hook)
    }

    // not really a loop, because it doesn't need to be for the two party case
    fn accept_loop(&mut self) -> Promise<(), Error> {
        let connection_state_ref = self.connection_state.clone();
        let bootstrap_cap = self.bootstrap_cap.clone();
        let handle = self.handle.clone();
        Promise::from_future(self.network.accept().map_ok(move |connection| {
            RpcSystem::get_connection_state(connection_state_ref,
                                            bootstrap_cap,
                                            connection,
                                            handle);
        }))
    }

    // If `connection_state_ref` is not already populated, populates it with a new
    // `ConnectionState` built from a local bootstrap capability and `connection`,
    // spawning any background tasks onto `handle`. Returns the resulting value
    // held in `connection_state_ref`.
    fn get_connection_state(connection_state_ref: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,
                            bootstrap_cap: Box<dyn ClientHook>,
                            connection: Box<dyn crate::Connection<VatId>>,
                            mut handle: crate::task_set::TaskSetHandle<Error>)
                            -> Rc<rpc::ConnectionState<VatId>>
    {
        // TODO this needs to be updated once we allow more general VatNetworks.
        let (tasks, result) = match *connection_state_ref.borrow() {
            Some(ref connection_state) => {
                // return early.
                return connection_state.clone()
            }
            None => {
                let (on_disconnect_fulfiller, on_disconnect_promise) =
                    oneshot::channel::<Promise<(), Error>>();
                let connection_state_ref1 = connection_state_ref.clone();
                handle.add(on_disconnect_promise.then(move |shutdown_promise| {
                    *connection_state_ref1.borrow_mut() = None;
                    match shutdown_promise {
                        Ok(s) => s,
                        Err(e) => Promise::err(Error::failed(format!("{}", e))),
                    }
                }));
                rpc::ConnectionState::new(bootstrap_cap, connection, on_disconnect_fulfiller)
            }
        };
        *connection_state_ref.borrow_mut() = Some(result.clone());
        handle.add(tasks);
        result
    }

    /// Returns a `Disconnector` future that can be run to cleanly close the connection to this `RpcSystem`'s network.
    /// You should get the `Disconnector` before you spawn the `RpcSystem`.
    pub fn get_disconnector(&self) -> rpc::Disconnector<VatId> {
        rpc::Disconnector::new(self.connection_state.clone())
    }
}

impl <VatId> Future for RpcSystem<VatId> where VatId: 'static {
    type Output = Result<(),Error>;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        Pin::new(&mut self.tasks).poll(cx)
    }
}

/// Creates a new local RPC client of type `C` out of an object that implements a server trait `S`.
pub fn new_client<C, S>(s: S) -> C where C: capnp::capability::FromServer<S> {
    capnp::capability::FromClientHook::new(Box::new(
        local::Client::new(Box::new(<C as capnp::capability::FromServer::<S>>::from_server(s)))))
}

/// Converts a promise for a client into a client that queues up any calls that arrive
/// before the promise resolves.
// TODO: figure out a better way to allow construction of promise clients.
pub fn new_promise_client<T, F>(client_promise: F) -> T
    where T: ::capnp::capability::FromClientHook,
          F: ::futures::Future<Output=Result<capnp::capability::Client,Error>>,
          F: 'static + Unpin
{
    let mut queued_client = crate::queued::Client::new(None);
    let weak_client = Rc::downgrade(&queued_client.inner);

    queued_client.drive(client_promise.then(move |r| {
        if let Some(queued_inner) = weak_client.upgrade() {
            crate::queued::ClientInner::resolve(&queued_inner, r.map(|c| c.hook));
        }
        Promise::ok(())
    }));

    T::new(Box::new(queued_client))
}

struct SystemTaskReaper;
impl crate::task_set::TaskReaper<Error> for SystemTaskReaper {
    fn task_failed(&mut self, error: Error) {
        println!("ERROR: {}", error);
    }
}

pub struct ImbuedMessageBuilder<A> where A: ::capnp::message::Allocator {
    builder: ::capnp::message::Builder<A>,
    cap_table: Vec<Option<Box<dyn (::capnp::private::capability::ClientHook)>>>,
}

impl <A> ImbuedMessageBuilder<A> where A: ::capnp::message::Allocator {
    pub fn new(allocator: A) -> Self {
        ImbuedMessageBuilder {
            builder: ::capnp::message::Builder::new(allocator),
            cap_table: Vec::new(),
        }
    }

    pub fn get_root<'a, T>(&'a mut self) -> ::capnp::Result<T>
        where T: ::capnp::traits::FromPointerBuilder<'a>
    {
        use capnp::traits::ImbueMut;
        let mut root: ::capnp::any_pointer::Builder = self.builder.get_root()?;
        root.imbue_mut(&mut self.cap_table);
        root.get_as()
    }

    pub fn set_root<From>(&mut self, value: From) -> ::capnp::Result<()>
        where From: ::capnp::traits::SetPointerBuilder
    {
        use capnp::traits::ImbueMut;
        let mut root: ::capnp::any_pointer::Builder = self.builder.get_root()?;
        root.imbue_mut(&mut self.cap_table);
        root.set_as(value)
    }
}

fn canceled_to_error(_e: futures::channel::oneshot::Canceled) -> Error {
        Error::failed(format!("oneshot was canceled"))
}
<commit_msg>fix link in capnp-rpc top-level doc comment<commit_after>// Copyright (c) 2013-2017 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! An implementation of the [Cap'n Proto remote procedure call](https://capnproto.org/rpc.html)
//! protocol. Includes all [Level 1](https://capnproto.org/rpc.html#protocol-features) features.
//!
//! # Example
//!
//! ```capnp
//! # Cap'n Proto schema
//! interface Foo {
//!     identity @0 (x: UInt32) -> (y: UInt32);
//! }
//! ```
//!
//! ```ignore
//! // Rust server defining an implementation of Foo.
//! struct FooImpl;
//! impl foo::Server for FooImpl {
//!     fn identity(&mut self,
//!                 params: foo::IdentityParams,
//!                 mut results: foo::IdentityResults)
//!                 -> Promise<(), ::capnp::Error>
//!     {
//!         let x = pry!(params.get()).get_x();
//!         results.get().set_y(x);
//!         Promise::ok(())
//!     }
//! }
//! ```
//!
//! ```ignore
//! // Rust client calling a remote implementation of Foo.
//! let mut request = foo_client.identity_request();
//! request.get().set_x(123);
//! let promise = request.send().promise.and_then(|response| {
//!     println!("results = {}", response.get()?.get_y());
//!     Ok(())
//! });
//! ```
//!
//! For a more complete example, see <https://github.com/capnproto/capnproto-rust/tree/master/capnp-rpc/examples/calculator>

use std::pin::Pin;
use std::task::{Context, Poll};
use futures::{Future, FutureExt, TryFutureExt};
use futures::channel::oneshot;
use capnp::Error;
use capnp::capability::Promise;
use capnp::private::capability::{ClientHook};
use std::cell::{RefCell};
use std::rc::{Rc};

use crate::task_set::TaskSet;
pub use crate::rpc::Disconnector;

/// Code generated from
/// [rpc.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc.capnp).
pub mod rpc_capnp;

/// Code generated from
/// [rpc-twoparty.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc-twoparty.capnp).
pub mod rpc_twoparty_capnp;

/// Like `try!()`, but for functions that return a `Promise<T, E>` rather than a `Result<T, E>`.
///
/// Unwraps a `Result<T, E>`. In the case of an error `Err(e)`, immediately returns from the
/// enclosing function with `Promise::err(e)`.
#[macro_export]
macro_rules! pry {
    ($expr:expr) => (
        match $expr {
            ::std::result::Result::Ok(val) => val,
            ::std::result::Result::Err(err) => {
                return ::capnp::capability::Promise::err(::std::convert::From::from(err))
            }
        })
}

mod broken;
mod local;
mod queued;
mod rpc;
mod attach;
mod sender_queue;
mod split;
mod task_set;
pub mod twoparty;

pub trait OutgoingMessage {
    fn get_body<'a>(&'a mut self) -> ::capnp::Result<::capnp::any_pointer::Builder<'a>>;
    fn get_body_as_reader<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;

    /// Sends the message. Returns a promise for the message that resolves once the send has completed.
    /// Dropping the returned promise does *not* cancel the send.
    fn send(self: Box<Self>)
            -> (Promise<Rc<::capnp::message::Builder<::capnp::message::HeapAllocator>>, ::capnp::Error>,
                Rc<::capnp::message::Builder<::capnp::message::HeapAllocator>>);

    fn take(self: Box<Self>) -> ::capnp::message::Builder<::capnp::message::HeapAllocator>;
}

pub trait IncomingMessage {
    fn get_body<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;
}

pub trait Connection<VatId> {
    fn get_peer_vat_id(&self) -> VatId;
    fn new_outgoing_message(&mut self, first_segment_word_size: u32) -> Box<dyn OutgoingMessage>;

    /// Waits for a message to be received and returns it.  If the read stream cleanly terminates,
    /// returns None. If any other problem occurs, returns an Error.
    fn receive_incoming_message(&mut self) -> Promise<Option<Box<dyn IncomingMessage>>, Error>;

    // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The
    // returned promise resolves after shutdown is complete.
    fn shutdown(&mut self, result: ::capnp::Result<()>) -> Promise<(), Error>;
}

pub trait VatNetwork<VatId> {
    /// Returns None if `hostId` refers to the local vat.
    fn connect(&mut self, host_id: VatId) -> Option<Box<dyn Connection<VatId>>>;

    /// Waits for the next incoming connection and return it.
    fn accept(&mut self) -> Promise<Box<dyn Connection<VatId>>, ::capnp::Error>;

    fn drive_until_shutdown(&mut self) -> Promise<(), Error>;
}

/// A portal to objects available on the network.
///
/// The RPC implemententation sits on top of an implementation of `VatNetwork`, which
/// determines how to form connections between vats. The RPC implementation determines
/// how to use such connections to manage object references and make method calls.
///
/// At the moment, this is all rather more general than it needs to be, because the only
/// implementation of `VatNetwork` is `twoparty::VatNetwork`. However, eventually we
/// will need to have more sophisticated `VatNetwork` implementations, in order to support
/// [level 3](https://capnproto.org/rpc.html#protocol-features) features.
///
/// An `RpcSystem` is a `Future` and needs to be driven by a task executor. A common way
/// accomplish that is to pass the `RpcSystem` to `tokio_core::reactor::Handle::spawn()`.
#[must_use = "futures do nothing unless polled"]
pub struct RpcSystem<VatId> where VatId: 'static {
    network: Box<dyn crate::VatNetwork<VatId>>,

    bootstrap_cap: Box<dyn ClientHook>,

    // XXX To handle three or more party networks, this should be a map from connection pointers
    // to connection states.
    connection_state: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,

    tasks: TaskSet<Error>,
    handle: crate::task_set::TaskSetHandle<Error>
}

impl <VatId> RpcSystem <VatId> {
    /// Constructs a new `RpcSystem` with the given network and bootstrap capability.
    pub fn new(
        mut network: Box<dyn crate::VatNetwork<VatId>>,
        bootstrap: Option<::capnp::capability::Client>) -> RpcSystem<VatId>
    {
        let bootstrap_cap = match bootstrap {
            Some(cap) => cap.hook,
            None => broken::new_cap(Error::failed("no bootstrap capability".to_string())),
        };
        let (mut handle, tasks) = TaskSet::new(Box::new(SystemTaskReaper));

        let mut handle1 = handle.clone();
        handle.add(network.drive_until_shutdown().then(move |r| {
            let r = match r {
                Ok(()) => Ok(()),
                Err(e) => {
                    if e.kind != ::capnp::ErrorKind::Disconnected {
                        // Don't report disconnects as an error.
                        Err(e)
                    } else {
                        Ok(())
                    }
                }
            };

            handle1.terminate(r);
            Promise::ok(())
        }));

        let mut result = RpcSystem {
            network: network,
            bootstrap_cap: bootstrap_cap,
            connection_state: Rc::new(RefCell::new(None)),

            tasks: tasks,
            handle: handle.clone(),
        };

        let accept_loop = result.accept_loop();
        handle.add(accept_loop);
        result
    }

    /// Connects to the given vat and returns its bootstrap interface.
    pub fn bootstrap<T>(&mut self, vat_id: VatId) -> T
        where T: ::capnp::capability::FromClientHook
    {
        let connection = match self.network.connect(vat_id) {
            Some(connection) => connection,
            None => {
                return T::new(self.bootstrap_cap.clone());
            }
        };
        let connection_state =
            RpcSystem::get_connection_state(self.connection_state.clone(),
                                            self.bootstrap_cap.clone(),
                                            connection, self.handle.clone());

        let hook = rpc::ConnectionState::bootstrap(connection_state.clone());
        T::new(hook)
    }

    // not really a loop, because it doesn't need to be for the two party case
    fn accept_loop(&mut self) -> Promise<(), Error> {
        let connection_state_ref = self.connection_state.clone();
        let bootstrap_cap = self.bootstrap_cap.clone();
        let handle = self.handle.clone();
        Promise::from_future(self.network.accept().map_ok(move |connection| {
            RpcSystem::get_connection_state(connection_state_ref,
                                            bootstrap_cap,
                                            connection,
                                            handle);
        }))
    }

    // If `connection_state_ref` is not already populated, populates it with a new
    // `ConnectionState` built from a local bootstrap capability and `connection`,
    // spawning any background tasks onto `handle`. Returns the resulting value
    // held in `connection_state_ref`.
    fn get_connection_state(connection_state_ref: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,
                            bootstrap_cap: Box<dyn ClientHook>,
                            connection: Box<dyn crate::Connection<VatId>>,
                            mut handle: crate::task_set::TaskSetHandle<Error>)
                            -> Rc<rpc::ConnectionState<VatId>>
    {
        // TODO this needs to be updated once we allow more general VatNetworks.
        let (tasks, result) = match *connection_state_ref.borrow() {
            Some(ref connection_state) => {
                // return early.
                return connection_state.clone()
            }
            None => {
                let (on_disconnect_fulfiller, on_disconnect_promise) =
                    oneshot::channel::<Promise<(), Error>>();
                let connection_state_ref1 = connection_state_ref.clone();
                handle.add(on_disconnect_promise.then(move |shutdown_promise| {
                    *connection_state_ref1.borrow_mut() = None;
                    match shutdown_promise {
                        Ok(s) => s,
                        Err(e) => Promise::err(Error::failed(format!("{}", e))),
                    }
                }));
                rpc::ConnectionState::new(bootstrap_cap, connection, on_disconnect_fulfiller)
            }
        };
        *connection_state_ref.borrow_mut() = Some(result.clone());
        handle.add(tasks);
        result
    }

    /// Returns a `Disconnector` future that can be run to cleanly close the connection to this `RpcSystem`'s network.
    /// You should get the `Disconnector` before you spawn the `RpcSystem`.
    pub fn get_disconnector(&self) -> rpc::Disconnector<VatId> {
        rpc::Disconnector::new(self.connection_state.clone())
    }
}

impl <VatId> Future for RpcSystem<VatId> where VatId: 'static {
    type Output = Result<(),Error>;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        Pin::new(&mut self.tasks).poll(cx)
    }
}

/// Creates a new local RPC client of type `C` out of an object that implements a server trait `S`.
pub fn new_client<C, S>(s: S) -> C where C: capnp::capability::FromServer<S> {
    capnp::capability::FromClientHook::new(Box::new(
        local::Client::new(Box::new(<C as capnp::capability::FromServer::<S>>::from_server(s)))))
}

/// Converts a promise for a client into a client that queues up any calls that arrive
/// before the promise resolves.
// TODO: figure out a better way to allow construction of promise clients.
pub fn new_promise_client<T, F>(client_promise: F) -> T
    where T: ::capnp::capability::FromClientHook,
          F: ::futures::Future<Output=Result<capnp::capability::Client,Error>>,
          F: 'static + Unpin
{
    let mut queued_client = crate::queued::Client::new(None);
    let weak_client = Rc::downgrade(&queued_client.inner);

    queued_client.drive(client_promise.then(move |r| {
        if let Some(queued_inner) = weak_client.upgrade() {
            crate::queued::ClientInner::resolve(&queued_inner, r.map(|c| c.hook));
        }
        Promise::ok(())
    }));

    T::new(Box::new(queued_client))
}

struct SystemTaskReaper;
impl crate::task_set::TaskReaper<Error> for SystemTaskReaper {
    fn task_failed(&mut self, error: Error) {
        println!("ERROR: {}", error);
    }
}

pub struct ImbuedMessageBuilder<A> where A: ::capnp::message::Allocator {
    builder: ::capnp::message::Builder<A>,
    cap_table: Vec<Option<Box<dyn (::capnp::private::capability::ClientHook)>>>,
}

impl <A> ImbuedMessageBuilder<A> where A: ::capnp::message::Allocator {
    pub fn new(allocator: A) -> Self {
        ImbuedMessageBuilder {
            builder: ::capnp::message::Builder::new(allocator),
            cap_table: Vec::new(),
        }
    }

    pub fn get_root<'a, T>(&'a mut self) -> ::capnp::Result<T>
        where T: ::capnp::traits::FromPointerBuilder<'a>
    {
        use capnp::traits::ImbueMut;
        let mut root: ::capnp::any_pointer::Builder = self.builder.get_root()?;
        root.imbue_mut(&mut self.cap_table);
        root.get_as()
    }

    pub fn set_root<From>(&mut self, value: From) -> ::capnp::Result<()>
        where From: ::capnp::traits::SetPointerBuilder
    {
        use capnp::traits::ImbueMut;
        let mut root: ::capnp::any_pointer::Builder = self.builder.get_root()?;
        root.imbue_mut(&mut self.cap_table);
        root.set_as(value)
    }
}

fn canceled_to_error(_e: futures::channel::oneshot::Canceled) -> Error {
        Error::failed(format!("oneshot was canceled"))
}
<|endoftext|>