<commit_before>/// RouteGraph defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot, tag, and channel.
/// Edges are also allowed to go to null, in which case they only have a destination slot and
/// channel. These are outputs.
/// Edges can also COME from null, in which case the source has the format (slot, channel)

use std::cmp;
use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use resman::ResMan;
use super::adjlist::AdjList;
use super::adjlist;
use super::effect;
use super::effect::Effect;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
struct EdgeWeight {
    from_slot: u32,
    from_ch: u8,
    to_slot: u32,
    to_ch: u8,
}

#[derive(Clone, Eq, PartialEq)]
pub enum NodeData {
    Effect(Rc<Effect>),
    Graph(DagHandle),
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct DagHandle {
    // None represents the Top-level DAG
    id: Option<u32>,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct PrimNodeHandle {
    id: u64,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct NodeHandle {
    dag_handle: DagHandle,
    node_handle: Option<PrimNodeHandle>,
}

#[derive(Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct Edge {
    dag_handle: DagHandle,
    from: Option<PrimNodeHandle>,
    to: Option<PrimNodeHandle>,
    weight: EdgeWeight,
}

#[derive(Debug)]
pub enum Error {
    /// Raised when an attempt to modify the graph would create a dependency cycle.
    WouldCycle,
    /// Raised on attempt to delete a node when it still has edges.
    NodeInUse,
    /// Raised on attempt to create a node with an id that's already in use.
    NodeExists,
    /// Error inside some Effect:: method
    EffectError(effect::Error),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

pub struct RouteGraph {
    // TODO: can make these non-zero for more efficient Option<NodeHandle> encoding
    dag_counter: u32,
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        RouteGraph {
            dag_counter: 0,
            edges: HashMap::new(),
            node_data: HashMap::new(),
        }
    }
    /*pub fn add_watcher(&mut self, mut watcher: Box<GraphWatcher>, do_replay: bool) {
        if do_replay {
            for node in self.iter_nodes() {
                watcher.on_add_node(node, &self.node_data[node]);
            }
            for edge in self.iter_edges() {
                watcher.on_add_edge(edge);
            }
        }
        self.watchers.push(watcher);
    }*/
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=&NodeHandle> + 'a {
        self.node_data.keys()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn add_dag(&mut self) -> DagHandle {
        let handle = DagHandle{ id: Some(self.dag_counter) };
        self.dag_counter += 1;
        handle
    }
    /// Try to create a node with the given handle/data.
    /// Will error if the handle is already in use.
    pub fn add_node(&mut self, handle: NodeHandle, node_data: NodeData) -> ResultE<()> {
        // Create storage for the node's outgoing edges
        match self.edges.entry(handle) {
            hash_map::Entry::Occupied(_) => Err(Error::NodeExists),
            hash_map::Entry::Vacant(entry) => { entry.insert(EdgeSet::new()); Ok(()) },
        }?;
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data.clone()).is_none());
        Ok(())
    }
    pub fn add_edge(&mut self, edge: Edge) -> ResultE<()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(Error::WouldCycle)
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, to: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        let dag_handle = from.dag_handle.clone();
        let dagnode_handle = NodeHandle::new(dag_handle, None);
        for candidate in self.edges[&from.to_full()].outbound.iter() {
            if self.are_edges_internally_connected(&self.node_data[&candidate.from_full()], &from, &candidate) {
                // See if we can reach `to` from the candidate
                match candidate.to {
                    // The edge we traversed keeps us inside the current DAG
                    Some(_) => if self.is_edge_reachable(candidate, to) {
                        return true
                    },
                    // The edge we traversed takes us out of the DAG.
                    // Consider all nodes aliased to this DAG;
                    //   for each one, consider all paths that lead back to it & continue the
                    //   search.
                    None => {
                        let search = NodeData::Graph(candidate.dag_handle);
                        for node in self.node_data_to_handles(&search) {
                            for edge_out in self.edges[&node].outbound.iter() {
                                // Consider all edges leaving this node that are reachable
                                if edge_out.weight.from_slot == to.weight.to_slot &&
                                    edge_out.weight.from_ch == to.weight.to_ch {
                                    for edge_in in self.paths_from_edge_to_node(edge_out, &node) {
                                        for edge in self.edges[&dagnode_handle].inbound.iter() {
                                            // Follow the edge back into this DAG.
                                            if edge_in.weight.to_slot == edge.weight.from_slot &&
                                                edge_in.weight.to_ch == edge.weight.from_ch {
                                                // Now we're back in the DAG; continue the search
                                                if self.is_edge_reachable(&edge, to) {
                                                    return true
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        false
    }
    /// Return all edges into `to` that are reachable from `from`.
    fn paths_from_edge_to_node<'a>(&'a self, from: &'a Edge, to: &'a NodeHandle) -> impl Iterator<Item=&'a Edge> + 'a {
        self.edges[to].inbound.iter().filter(move |e| {
            self.is_edge_reachable(&from, e)
        })
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, node_data: &NodeData, from: &Edge, to: &Edge) -> bool {
        match *node_data {
            NodeData::Effect(ref effect) => effect.are_slots_connected(
                from.weight.to_slot, from.weight.to_ch,
                to.weight.from_slot, to.weight.from_ch),
            // See if there's a path from (None->from.to) to (to.from->None) within the dag
            NodeData::Graph(ref dag_handle) => {
                let dagnode_handle = NodeHandle::new(dag_handle.clone(), None);
                // Consider all edges from (None->from.to)
                self.edges[&dagnode_handle].outbound.iter().filter(|new_from| {
                    new_from.weight.from_slot == from.weight.to_slot &&
                        new_from.weight.from_ch == from.weight.to_ch
                })
                // Check if there's a path to (None) and that the edge to (None) is (to.from->None)
                .any(|new_from| {
                    self.paths_from_edge_to_node(new_from, &dagnode_handle).any(|new_to| {
                        new_to.weight.to_slot == to.weight.from_slot &&
                            new_to.weight.to_ch == to.weight.from_ch
                    })
                })
            }
        }
    }
    fn node_data_to_handles<'a>(&'a self, data: &'a NodeData) -> impl Iterator<Item=NodeHandle> + 'a {
        self.node_data.iter().filter(move |&(handle, node)| {
            node == data
        }).map(|(handle, node)| {
            handle.clone()
        })
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, in_ch: u8, out_slot: u32, out_ch: u8) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::new(DagHandle { id: None }, None);
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot && edge.weight.from_ch == in_ch
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot && edge.weight.to_ch == out_ch
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> ResultE<()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(Error::NodeInUse)
                }
            }
        };
        if let Ok(_) = ok_to_delete {
            // delete the data associated with this node
            self.node_data.remove(&node);
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
    }

    pub fn to_adjlist(&self) -> AdjList {
        // Map Effect -> EffectMeta
        let nodes = self.node_data.iter().map(|(handle, data)| {
            (handle.clone(), data.to_adjlist_data())
        }).collect();
        // Doubly-linked edges -> singly-linked
        let edges = self.edges.iter().flat_map(|(_key, edgeset)| {
            edgeset.outbound.clone().into_iter()
        }).collect();

        AdjList {
            nodes: nodes,
            edges: edges,
        }
    }
    pub fn from_adjlist(adj: AdjList, res: &ResMan) -> ResultE<Self> {
        // Unwrap struct fields to local variables
        let (nodes, edges) = (adj.nodes, adj.edges);

        // Map EffectMeta -> Effect and also determine the highest ids in use
        let mut dag_counter = 0;
        let nodes: ResultE<HashMap<NodeHandle, NodeData>> = nodes.into_iter().map(|(handle, data)| {
            if let Some(dag_hnd) = handle.dag_handle.id {
                dag_counter = cmp::max(dag_counter, dag_hnd);
            }
            let decoded_data = match data {
                adjlist::NodeData::Effect(meta) =>
                    NodeData::Effect(Effect::from_meta(meta, res)?),
                adjlist::NodeData::Graph(dag_handle) =>
                    NodeData::Graph(dag_handle),
            };
            Ok((handle.clone(), decoded_data))
        }).collect();
        // Type deduction isn't smart enough to unwrap nodes in above statement.
        let nodes = nodes?;

        // Build self with only nodes and no edges
        let mut me = Self {
            dag_counter: dag_counter,
            edges: HashMap::new(),
            node_data: nodes,
        };

        // Add the edges one at a time, enforcing zero cycles
        for edge in edges.into_iter() {
            me.add_edge(edge)?
        }
        Ok(me)
    }
}

impl NodeHandle {
    pub fn toplevel() -> Self {
        NodeHandle::new(DagHandle::toplevel(), None)
    }
    pub fn new(dag: DagHandle, node: Option<PrimNodeHandle>) -> Self {
        Self {
            dag_handle: dag,
            node_handle: node,
        }
    }
    pub fn dag_handle(&self) -> &DagHandle {
        &self.dag_handle
    }
    pub fn node_handle(&self) -> &Option<PrimNodeHandle> {
        &self.node_handle
    }
}

impl Edge {
    fn dag_handle(&self) -> &DagHandle {
        &self.dag_handle
    }
    pub fn from_full(&self) -> NodeHandle {
        NodeHandle {
            dag_handle: self.dag_handle,
            node_handle: self.from,
        }
    }
    pub fn to_full(&self) -> NodeHandle {
        NodeHandle {
            dag_handle: self.dag_handle,
            node_handle: self.to,
        }
    }
    pub fn to_slot(&self) -> u32 {
        self.weight.to_slot
    }
    pub fn to_ch(&self) -> u8 {
        self.weight.to_ch
    }
    pub fn from_slot(&self) -> u32 {
        self.weight.from_slot
    }
    pub fn from_ch(&self) -> u8 {
        self.weight.from_ch
    }
}

impl NodeData {
    fn is_effect(&self) -> bool {
        match *self {
            NodeData::Effect(_) => true,
            _ => false,
        }
    }
    /// NodeData normally encodes references to actual node implementations -
    /// in order to know their internal connections, etc.
    /// This transforms it into a type that is suitable for transmission, i.e.
    /// metadata explaining how to locate the correct effect implementation.
    fn to_adjlist_data(&self) -> adjlist::NodeData {
        match *self {
            NodeData::Effect(ref effect) => adjlist::NodeData::Effect(effect.meta().clone()),
            NodeData::Graph(ref dag) => adjlist::NodeData::Graph(dag.clone()),
        }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}

impl DagHandle {
    fn toplevel() -> Self {
        DagHandle {
            id: None
        }
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}
<commit_msg>Remove commented-out code.<commit_after>/// RouteGraph defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot, tag, and channel.
/// Edges are also allowed to go to null, in which case they only have a destination slot and
/// channel. These are outputs.
/// Edges can also COME from null, in which case the source has the format (slot, channel)

use std::cmp;
use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use resman::ResMan;
use super::adjlist::AdjList;
use super::adjlist;
use super::effect;
use super::effect::Effect;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
struct EdgeWeight {
    from_slot: u32,
    from_ch: u8,
    to_slot: u32,
    to_ch: u8,
}

#[derive(Clone, Eq, PartialEq)]
pub enum NodeData {
    Effect(Rc<Effect>),
    Graph(DagHandle),
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct DagHandle {
    // None represents the Top-level DAG
    id: Option<u32>,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct PrimNodeHandle {
    id: u64,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct NodeHandle {
    dag_handle: DagHandle,
    node_handle: Option<PrimNodeHandle>,
}

#[derive(Clone, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct Edge {
    dag_handle: DagHandle,
    from: Option<PrimNodeHandle>,
    to: Option<PrimNodeHandle>,
    weight: EdgeWeight,
}

#[derive(Debug)]
pub enum Error {
    /// Raised when an attempt to modify the graph would create a dependency cycle.
    WouldCycle,
    /// Raised on attempt to delete a node when it still has edges.
    NodeInUse,
    /// Raised on attempt to create a node with an id that's already in use.
    NodeExists,
    /// Error inside some Effect:: method
    EffectError(effect::Error),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

pub struct RouteGraph {
    // TODO: can make these non-zero for more efficient Option<NodeHandle> encoding
    dag_counter: u32,
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        RouteGraph {
            dag_counter: 0,
            edges: HashMap::new(),
            node_data: HashMap::new(),
        }
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=&NodeHandle> + 'a {
        self.node_data.keys()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn add_dag(&mut self) -> DagHandle {
        let handle = DagHandle{ id: Some(self.dag_counter) };
        self.dag_counter += 1;
        handle
    }
    /// Try to create a node with the given handle/data.
    /// Will error if the handle is already in use.
    pub fn add_node(&mut self, handle: NodeHandle, node_data: NodeData) -> ResultE<()> {
        // Create storage for the node's outgoing edges
        match self.edges.entry(handle) {
            hash_map::Entry::Occupied(_) => Err(Error::NodeExists),
            hash_map::Entry::Vacant(entry) => { entry.insert(EdgeSet::new()); Ok(()) },
        }?;
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data.clone()).is_none());
        Ok(())
    }
    pub fn add_edge(&mut self, edge: Edge) -> ResultE<()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(Error::WouldCycle)
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, to: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        let dag_handle = from.dag_handle.clone();
        let dagnode_handle = NodeHandle::new(dag_handle, None);
        for candidate in self.edges[&from.to_full()].outbound.iter() {
            if self.are_edges_internally_connected(&self.node_data[&candidate.from_full()], &from, &candidate) {
                // See if we can reach `to` from the candidate
                match candidate.to {
                    // The edge we traversed keeps us inside the current DAG
                    Some(_) => if self.is_edge_reachable(candidate, to) {
                        return true
                    },
                    // The edge we traversed takes us out of the DAG.
                    // Consider all nodes aliased to this DAG;
                    //   for each one, consider all paths that lead back to it & continue the
                    //   search.
                    None => {
                        let search = NodeData::Graph(candidate.dag_handle);
                        for node in self.node_data_to_handles(&search) {
                            for edge_out in self.edges[&node].outbound.iter() {
                                // Consider all edges leaving this node that are reachable
                                if edge_out.weight.from_slot == to.weight.to_slot &&
                                    edge_out.weight.from_ch == to.weight.to_ch {
                                    for edge_in in self.paths_from_edge_to_node(edge_out, &node) {
                                        for edge in self.edges[&dagnode_handle].inbound.iter() {
                                            // Follow the edge back into this DAG.
                                            if edge_in.weight.to_slot == edge.weight.from_slot &&
                                                edge_in.weight.to_ch == edge.weight.from_ch {
                                                // Now we're back in the DAG; continue the search
                                                if self.is_edge_reachable(&edge, to) {
                                                    return true
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        false
    }
    /// Return all edges into `to` that are reachable from `from`.
    fn paths_from_edge_to_node<'a>(&'a self, from: &'a Edge, to: &'a NodeHandle) -> impl Iterator<Item=&'a Edge> + 'a {
        self.edges[to].inbound.iter().filter(move |e| {
            self.is_edge_reachable(&from, e)
        })
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, node_data: &NodeData, from: &Edge, to: &Edge) -> bool {
        match *node_data {
            NodeData::Effect(ref effect) => effect.are_slots_connected(
                from.weight.to_slot, from.weight.to_ch,
                to.weight.from_slot, to.weight.from_ch),
            // See if there's a path from (None->from.to) to (to.from->None) within the dag
            NodeData::Graph(ref dag_handle) => {
                let dagnode_handle = NodeHandle::new(dag_handle.clone(), None);
                // Consider all edges from (None->from.to)
                self.edges[&dagnode_handle].outbound.iter().filter(|new_from| {
                    new_from.weight.from_slot == from.weight.to_slot &&
                        new_from.weight.from_ch == from.weight.to_ch
                })
                // Check if there's a path to (None) and that the edge to (None) is (to.from->None)
                .any(|new_from| {
                    self.paths_from_edge_to_node(new_from, &dagnode_handle).any(|new_to| {
                        new_to.weight.to_slot == to.weight.from_slot &&
                            new_to.weight.to_ch == to.weight.from_ch
                    })
                })
            }
        }
    }
    fn node_data_to_handles<'a>(&'a self, data: &'a NodeData) -> impl Iterator<Item=NodeHandle> + 'a {
        self.node_data.iter().filter(move |&(handle, node)| {
            node == data
        }).map(|(handle, node)| {
            handle.clone()
        })
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, in_ch: u8, out_slot: u32, out_ch: u8) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::new(DagHandle { id: None }, None);
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot && edge.weight.from_ch == in_ch
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot && edge.weight.to_ch == out_ch
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> ResultE<()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(Error::NodeInUse)
                }
            }
        };
        if let Ok(_) = ok_to_delete {
            // delete the data associated with this node
            self.node_data.remove(&node);
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
    }

    pub fn to_adjlist(&self) -> AdjList {
        // Map Effect -> EffectMeta
        let nodes = self.node_data.iter().map(|(handle, data)| {
            (handle.clone(), data.to_adjlist_data())
        }).collect();
        // Doubly-linked edges -> singly-linked
        let edges = self.edges.iter().flat_map(|(_key, edgeset)| {
            edgeset.outbound.clone().into_iter()
        }).collect();

        AdjList {
            nodes: nodes,
            edges: edges,
        }
    }
    pub fn from_adjlist(adj: AdjList, res: &ResMan) -> ResultE<Self> {
        // Unwrap struct fields to local variables
        let (nodes, edges) = (adj.nodes, adj.edges);

        // Map EffectMeta -> Effect and also determine the highest ids in use
        let mut dag_counter = 0;
        let nodes: ResultE<HashMap<NodeHandle, NodeData>> = nodes.into_iter().map(|(handle, data)| {
            if let Some(dag_hnd) = handle.dag_handle.id {
                dag_counter = cmp::max(dag_counter, dag_hnd);
            }
            let decoded_data = match data {
                adjlist::NodeData::Effect(meta) =>
                    NodeData::Effect(Effect::from_meta(meta, res)?),
                adjlist::NodeData::Graph(dag_handle) =>
                    NodeData::Graph(dag_handle),
            };
            Ok((handle.clone(), decoded_data))
        }).collect();
        // Type deduction isn't smart enough to unwrap nodes in above statement.
        let nodes = nodes?;

        // Build self with only nodes and no edges
        let mut me = Self {
            dag_counter: dag_counter,
            edges: HashMap::new(),
            node_data: nodes,
        };

        // Add the edges one at a time, enforcing zero cycles
        for edge in edges.into_iter() {
            me.add_edge(edge)?
        }
        Ok(me)
    }
}

impl NodeHandle {
    pub fn toplevel() -> Self {
        NodeHandle::new(DagHandle::toplevel(), None)
    }
    pub fn new(dag: DagHandle, node: Option<PrimNodeHandle>) -> Self {
        Self {
            dag_handle: dag,
            node_handle: node,
        }
    }
    pub fn dag_handle(&self) -> &DagHandle {
        &self.dag_handle
    }
    pub fn node_handle(&self) -> &Option<PrimNodeHandle> {
        &self.node_handle
    }
}

impl Edge {
    fn dag_handle(&self) -> &DagHandle {
        &self.dag_handle
    }
    pub fn from_full(&self) -> NodeHandle {
        NodeHandle {
            dag_handle: self.dag_handle,
            node_handle: self.from,
        }
    }
    pub fn to_full(&self) -> NodeHandle {
        NodeHandle {
            dag_handle: self.dag_handle,
            node_handle: self.to,
        }
    }
    pub fn to_slot(&self) -> u32 {
        self.weight.to_slot
    }
    pub fn to_ch(&self) -> u8 {
        self.weight.to_ch
    }
    pub fn from_slot(&self) -> u32 {
        self.weight.from_slot
    }
    pub fn from_ch(&self) -> u8 {
        self.weight.from_ch
    }
}

impl NodeData {
    fn is_effect(&self) -> bool {
        match *self {
            NodeData::Effect(_) => true,
            _ => false,
        }
    }
    /// NodeData normally encodes references to actual node implementations -
    /// in order to know their internal connections, etc.
    /// This transforms it into a type that is suitable for transmission, i.e.
    /// metadata explaining how to locate the correct effect implementation.
    fn to_adjlist_data(&self) -> adjlist::NodeData {
        match *self {
            NodeData::Effect(ref effect) => adjlist::NodeData::Effect(effect.meta().clone()),
            NodeData::Graph(ref dag) => adjlist::NodeData::Graph(dag.clone()),
        }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}

impl DagHandle {
    fn toplevel() -> Self {
        DagHandle {
            id: None
        }
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}
<|endoftext|>


<commit_before>use crate::loom::sync::{Arc, Mutex};
use crate::time::driver::ClockTime;
use std::fmt;

/// Handle to time driver instance.
#[derive(Clone)]
pub(crate) struct Handle {
    time_source: ClockTime,
    inner: Arc<Mutex<super::Inner>>,
}

impl Handle {
    /// Creates a new timer `Handle` from a shared `Inner` timer state.
    pub(super) fn new(inner: Arc<Mutex<super::Inner>>) -> Self {
        let time_source = inner.lock().time_source.clone();
        Handle { time_source, inner }
    }

    /// Returns the time source associated with this handle
    pub(super) fn time_source(&self) -> &ClockTime {
        &self.time_source
    }

    /// Locks the driver's inner structure
    pub(super) fn lock(&self) -> crate::loom::sync::MutexGuard<'_, super::Inner> {
        self.inner.lock()
    }
}

cfg_rt! {
    impl Handle {
        /// Tries to get a handle to the current timer.
        ///
        /// # Panics
        ///
        /// This function panics if there is no current timer set.
        ///
        /// It can be triggered when `Builder::enable_time()` or
        /// `Builder::enable_all()` are not included in the builder.
        ///
        /// It can also panic whenever a timer is created ouClockTimeide of a
        /// Tokio runtime. That is why `rt.block_on(delay_for(...))` will panic,
        /// since the function is executed ouClockTimeide of the runtime.
        /// Whereas `rt.block_on(async {delay_for(...).await})` doesn't panic.
        /// And this is because wrapping the function on an async makes it lazy,
        /// and so gets executed inside the runtime successfuly without
        /// panicking.
        pub(crate) fn current() -> Self {
            crate::runtime::context::time_handle()
                .expect("there is no timer running, must be called from the context of Tokio runtime")
        }
    }
}

cfg_not_rt! {
    impl Handle {
        /// Tries to get a handle to the current timer.
        ///
        /// # Panics
        ///
        /// This function panics if there is no current timer set.
        ///
        /// It can be triggered when `Builder::enable_time()` or
        /// `Builder::enable_all()` are not included in the builder.
        ///
        /// It can also panic whenever a timer is created ouClockTimeide of a Tokio
        /// runtime. That is why `rt.block_on(delay_for(...))` will panic,
        /// since the function is executed ouClockTimeide of the runtime.
        /// Whereas `rt.block_on(async {delay_for(...).await})` doesn't
        /// panic. And this is because wrapping the function on an async makes it
        /// lazy, and so geClockTime executed inside the runtime successfuly without
        /// panicking.
        pub(crate) fn current() -> Self {
            panic!("there is no timer running, must be called from the context of Tokio runtime or \
            `rt` is not enabled")
        }
    }
}

impl fmt::Debug for Handle {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Handle")
    }
}
<commit_msg>time: replace 'ouClockTimeide' in internal docs with 'outside' (#3171)<commit_after>use crate::loom::sync::{Arc, Mutex};
use crate::time::driver::ClockTime;
use std::fmt;

/// Handle to time driver instance.
#[derive(Clone)]
pub(crate) struct Handle {
    time_source: ClockTime,
    inner: Arc<Mutex<super::Inner>>,
}

impl Handle {
    /// Creates a new timer `Handle` from a shared `Inner` timer state.
    pub(super) fn new(inner: Arc<Mutex<super::Inner>>) -> Self {
        let time_source = inner.lock().time_source.clone();
        Handle { time_source, inner }
    }

    /// Returns the time source associated with this handle
    pub(super) fn time_source(&self) -> &ClockTime {
        &self.time_source
    }

    /// Locks the driver's inner structure
    pub(super) fn lock(&self) -> crate::loom::sync::MutexGuard<'_, super::Inner> {
        self.inner.lock()
    }
}

cfg_rt! {
    impl Handle {
        /// Tries to get a handle to the current timer.
        ///
        /// # Panics
        ///
        /// This function panics if there is no current timer set.
        ///
        /// It can be triggered when `Builder::enable_time()` or
        /// `Builder::enable_all()` are not included in the builder.
        ///
        /// It can also panic whenever a timer is created outside of a
        /// Tokio runtime. That is why `rt.block_on(delay_for(...))` will panic,
        /// since the function is executed outside of the runtime.
        /// Whereas `rt.block_on(async {delay_for(...).await})` doesn't panic.
        /// And this is because wrapping the function on an async makes it lazy,
        /// and so gets executed inside the runtime successfuly without
        /// panicking.
        pub(crate) fn current() -> Self {
            crate::runtime::context::time_handle()
                .expect("there is no timer running, must be called from the context of Tokio runtime")
        }
    }
}

cfg_not_rt! {
    impl Handle {
        /// Tries to get a handle to the current timer.
        ///
        /// # Panics
        ///
        /// This function panics if there is no current timer set.
        ///
        /// It can be triggered when `Builder::enable_time()` or
        /// `Builder::enable_all()` are not included in the builder.
        ///
        /// It can also panic whenever a timer is created outside of a Tokio
        /// runtime. That is why `rt.block_on(delay_for(...))` will panic,
        /// since the function is executed outside of the runtime.
        /// Whereas `rt.block_on(async {delay_for(...).await})` doesn't
        /// panic. And this is because wrapping the function on an async makes it
        /// lazy, and so outside executed inside the runtime successfuly without
        /// panicking.
        pub(crate) fn current() -> Self {
            panic!("there is no timer running, must be called from the context of Tokio runtime or \
            `rt` is not enabled")
        }
    }
}

impl fmt::Debug for Handle {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Handle")
    }
}
<|endoftext|>


<commit_before>//! Warning: extreme macros

/// This macro creates structs that implement `ToTable` and `FromTable`.
///
/// # Examples:
///
/// ```rust
/// lua_convertible! {
///     #[derive(Debug)]
///     // #[attribtue]
///     struct Point {
///         x: i32,
///         y: i32
///     }
/// }
/// ```
#[macro_export]
macro_rules! lua_convertible {
    (  $(#[$attr:meta])*
       struct $name:ident { $($fname:ident : $ftype:ty),+  }  ) => {

        $(#[$attr])*
        pub struct $name {
            $($fname: $ftype),+
        }

        impl $crate::convert::ToTable for $name {
            fn to_table(self) -> hlua::any::AnyLuaValue {
                hlua::any::AnyLuaValue::LuaArray(vec![
                    $(  (hlua::any::AnyLuaValue::LuaString(stringify!($fname).to_string()),
                         self.$fname.to_table())  ),+
                ])
            }
        }

        impl $crate::convert::FromTable for $name {
            #[allow(unused_variables)]
            fn from_table(decoder: $crate::convert::LuaDecoder) ->
                $crate::convert::ConvertResult<$name> {
                $(  let (decoder, $fname) =
                    try!(decoder.read_field(stringify!($fname).to_string())); )+

                Ok($name {
                    $( $fname: $fname ),+
                })
            }
        }
    }
}
/// Creates a struct and implements `ToJson` and `Decodeable` from
/// rustc_serialize.
#[macro_export]
macro_rules! json_convertible {
    (  $(#[$attr:meta])*
       struct $name:ident { $($fname:ident : $ftype:ty),+  }  ) => {

        $(#[$attr])*
        pub struct $name {
            $($fname: $ftype),+
        }

        impl ::rustc_serialize::json::ToJson for $name {
            fn to_json(&self) -> ::rustc_serialize::json::Json {
                let mut tree = ::std::collections::BTreeMap::new();
                $( tree.insert(stringify!($fname).to_string(),
                                self.$fname.to_json()); )+
                ::rustc_serialize::json::Json::Object(tree)
            }
        }

        impl ::rustc_serialize::Decodable for $name {
            fn decode<D: ::rustc_serialize::Decoder>(d: &mut D) -> Result<$name, D::Error> {
                $( let $fname = try!(d.read_struct_field(
                    stringify!($fname), 0usize,
                    |f| ::rustc_serialize::Decodable::decode(f))); )+

                Ok($name {
                    $( $fname: $fname ),+
                })
            }
        }
    }
}
/// Create a keypress using fewer keystrokes. Provides a custom panic method.
#[macro_export]
macro_rules! keypress {
    ($modifier:expr, $key:expr) => {
        $crate::keys::KeyPress::from_key_names(&[$modifier],
                                 $key)
            .expect(concat!("Unable to create keypress from macro with ",
                            $modifier, " and ", $key))
    };
}

/// Return from a test method if DUMMY_RUSTWLC is defined.
#[cfg(test)]
macro_rules! require_rustwlc {
    () => {
        if cfg!(test) {
            return;
        }
    }
}

/// Create a dbus interface object.
///
/// Given the path and name of a dbus interface
/// and a series of methods with type ipc::DBusResult, this macro
/// generates a big function `setup(&mut DBusFactory) -> DBusObjPath`
/// which will call the `Factory`'s `add_*` methods properly.
///
/// Currently limited to one dbus interface per invocation and requires setting
/// the name of the outputs.
macro_rules! dbus_interface {
    ( path: $obj_path:expr; name: $obj_name:expr;
      $(fn $fn_name:ident($($in_name:ident : $in_ty:ty),*)
                          -> $out_name:ident : $out_ty:ty { $($inner:tt)* })+ ) => {
        #[warn(dead_code)]
        pub fn setup(factory: &mut $crate::ipc::DBusFactory) -> $crate::ipc::DBusObjPath {
            return factory.object_path($obj_path, ()).introspectable()
                .add(factory.interface($obj_name, ())
                     $(
                         .add_m(factory.method(stringify!(fn_name), (),
                                move |msg| {
                                    let args_iter = msg.msg.iter_init();
                                    $(
                                        let $in_name: $in_ty = args_iter.read::<$in_ty>()
                                            .expect("oopslol");
                                    )*
                                    let result = $fn_name($($in_name),*);
                                    match result {
                                        Ok(value) => {
                                            let dbus_return = msg.msg.method_return().append1(value);
                                            Ok(vec![dbus_return])
                                        },
                                        Err(err) => {
                                            Err()
                                        }
                                    }
                                    let dbus_return = msg.msg.method_return().append1(result);
                                    Ok(vec![dbus_return])
                                }).outarg::<$out_ty, _>(stringify!($out_name))
                            )
                     )*
                );
        }
        $(
            #[allow(non_snake_case)]
            #[warn(dead_code)]
            fn $fn_name( $($in_name: $in_ty),* ) -> $out_ty {
                $($inner)*
            }
        )*
    };
}

#[cfg(test)]
mod tests {
    use super::super::convert::{ToTable, FromTable, LuaDecoder};
    use hlua;
    use rustc_serialize::Decodable;
    use rustc_serialize::json::{Decoder, ToJson};

    lua_convertible! {
        #[derive(Debug, Clone, PartialEq)]
        struct Point {
            x: f32,
            y: f32
        }
    }

    json_convertible! {
        #[derive(Debug, Clone, PartialEq)]
        struct Rectangle {
            height: u32,
            width: u32
        }
    }

    #[test]
    fn require_rustwlc() {
        require_rustwlc!();
        // If we're here we can use rustwlc.
        // If we tried to get a view or something it'd fail though.
        let _ = keypress!("Ctrl", "p");
    }

    #[test]
    fn lua_convertible() {
        let point = Point { x: 0f32, y: 0f32 };
        let lua_point = point.clone().to_table();
        let maybe_point = Point::from_table(LuaDecoder::new(lua_point));
        let parsed_point = maybe_point.expect("Unable to parse point!");
        assert_eq!(parsed_point, point);
    }

    #[test]
    fn json_convertible() {
        let rect = Rectangle { height: 1u32, width: 2u32 };
        let json_rect = rect.to_json();
        let maybe_rect = Rectangle::decode(&mut Decoder::new(json_rect));
        let parsed_rect = maybe_rect.expect("Unable to parse rectangle!");
        assert_eq!(parsed_rect, rect);
    }

    #[test]
    fn keypress() {
        require_rustwlc!();
        use super::super::keys::KeyPress;
        use std::hash::{SipHasher, Hash};

        let press = KeyPress::from_key_names(&["Ctrl"], "p")
            .expect("Unable to construct regular keypress");
        let press_macro = keypress!("Ctrl", "p");
        let mut hasher = SipHasher::new();
        assert!(press.hash(&mut hasher) == press_macro.hash(&mut hasher),
                "Hashes do not match");
        assert_eq!(press, press_macro);
    }
}
<commit_msg>Fix DBus macro<commit_after>//! Warning: extreme macros

/// This macro creates structs that implement `ToTable` and `FromTable`.
///
/// # Examples:
///
/// ```rust
/// lua_convertible! {
///     #[derive(Debug)]
///     // #[attribtue]
///     struct Point {
///         x: i32,
///         y: i32
///     }
/// }
/// ```
#[macro_export]
macro_rules! lua_convertible {
    (  $(#[$attr:meta])*
       struct $name:ident { $($fname:ident : $ftype:ty),+  }  ) => {

        $(#[$attr])*
        pub struct $name {
            $($fname: $ftype),+
        }

        impl $crate::convert::ToTable for $name {
            fn to_table(self) -> hlua::any::AnyLuaValue {
                hlua::any::AnyLuaValue::LuaArray(vec![
                    $(  (hlua::any::AnyLuaValue::LuaString(stringify!($fname).to_string()),
                         self.$fname.to_table())  ),+
                ])
            }
        }

        impl $crate::convert::FromTable for $name {
            #[allow(unused_variables)]
            fn from_table(decoder: $crate::convert::LuaDecoder) ->
                $crate::convert::ConvertResult<$name> {
                $(  let (decoder, $fname) =
                    try!(decoder.read_field(stringify!($fname).to_string())); )+

                Ok($name {
                    $( $fname: $fname ),+
                })
            }
        }
    }
}
/// Creates a struct and implements `ToJson` and `Decodeable` from
/// rustc_serialize.
#[macro_export]
macro_rules! json_convertible {
    (  $(#[$attr:meta])*
       struct $name:ident { $($fname:ident : $ftype:ty),+  }  ) => {

        $(#[$attr])*
        pub struct $name {
            $($fname: $ftype),+
        }

        impl ::rustc_serialize::json::ToJson for $name {
            fn to_json(&self) -> ::rustc_serialize::json::Json {
                let mut tree = ::std::collections::BTreeMap::new();
                $( tree.insert(stringify!($fname).to_string(),
                                self.$fname.to_json()); )+
                ::rustc_serialize::json::Json::Object(tree)
            }
        }

        impl ::rustc_serialize::Decodable for $name {
            fn decode<D: ::rustc_serialize::Decoder>(d: &mut D) -> Result<$name, D::Error> {
                $( let $fname = try!(d.read_struct_field(
                    stringify!($fname), 0usize,
                    |f| ::rustc_serialize::Decodable::decode(f))); )+

                Ok($name {
                    $( $fname: $fname ),+
                })
            }
        }
    }
}
/// Create a keypress using fewer keystrokes. Provides a custom panic method.
#[macro_export]
macro_rules! keypress {
    ($modifier:expr, $key:expr) => {
        $crate::keys::KeyPress::from_key_names(&[$modifier],
                                 $key)
            .expect(concat!("Unable to create keypress from macro with ",
                            $modifier, " and ", $key))
    };
}

/// Return from a test method if DUMMY_RUSTWLC is defined.
#[cfg(test)]
macro_rules! require_rustwlc {
    () => {
        if cfg!(test) {
            return;
        }
    }
}

/// Create a dbus interface object.
///
/// Given the path and name of a dbus interface
/// and a series of methods with type ipc::DBusResult, this macro
/// generates a big function `setup(&mut DBusFactory) -> DBusObjPath`
/// which will call the `Factory`'s `add_*` methods properly.
///
/// Currently limited to one dbus interface per invocation and requires setting
/// the name of the outputs.
macro_rules! dbus_interface {
    ( path: $obj_path:expr; name: $obj_name:expr;
      $(fn $fn_name:ident($($in_name:ident : $in_ty:ty),*)
                          -> $out_name:ident : DBusResult< $out_ty_inner:ty > { $($inner:tt)* })+ ) => {
        #[warn(dead_code)]
        pub fn setup(factory: &mut $crate::ipc::DBusFactory) -> $crate::ipc::DBusObjPath {
            return factory.object_path($obj_path, ()).introspectable()
                .add(factory.interface($obj_name, ())
                     $(
                         .add_m(factory.method(stringify!($fn_name), (),
                                move |msg| {
                                    let mut args_iter = msg.msg.iter_init();
                                    $(
                                        let $in_name: $in_ty = args_iter.read::<$in_ty>()
                                            .expect("oopslol");
                                    )*
                                    let result = $fn_name($($in_name),*);
                                    match result {
                                        Ok(value) => {
                                            let dbus_return = msg.msg.method_return().append(value);
                                            return Ok(vec![dbus_return])
                                        },
                                        Err(err) => {
                                            return Err(err)
                                        }
                                    }
                                }).outarg::<$out_ty_inner, _>(stringify!($out_name))
                            )
                     )*
                );
        }
        $(
            #[allow(non_snake_case)]
            #[warn(dead_code)]
            fn $fn_name( $($in_name: $in_ty),* )
                         -> $crate::ipc::DBusResult<$out_ty_inner> {
                $($inner)*
            }
        )*
    };
}

#[cfg(test)]
mod tests {
    use super::super::convert::{ToTable, FromTable, LuaDecoder};
    use hlua;
    use rustc_serialize::Decodable;
    use rustc_serialize::json::{Decoder, ToJson};

    lua_convertible! {
        #[derive(Debug, Clone, PartialEq)]
        struct Point {
            x: f32,
            y: f32
        }
    }

    json_convertible! {
        #[derive(Debug, Clone, PartialEq)]
        struct Rectangle {
            height: u32,
            width: u32
        }
    }

    #[test]
    fn require_rustwlc() {
        require_rustwlc!();
        // If we're here we can use rustwlc.
        // If we tried to get a view or something it'd fail though.
        let _ = keypress!("Ctrl", "p");
    }

    #[test]
    fn lua_convertible() {
        let point = Point { x: 0f32, y: 0f32 };
        let lua_point = point.clone().to_table();
        let maybe_point = Point::from_table(LuaDecoder::new(lua_point));
        let parsed_point = maybe_point.expect("Unable to parse point!");
        assert_eq!(parsed_point, point);
    }

    #[test]
    fn json_convertible() {
        let rect = Rectangle { height: 1u32, width: 2u32 };
        let json_rect = rect.to_json();
        let maybe_rect = Rectangle::decode(&mut Decoder::new(json_rect));
        let parsed_rect = maybe_rect.expect("Unable to parse rectangle!");
        assert_eq!(parsed_rect, rect);
    }

    #[test]
    fn keypress() {
        require_rustwlc!();
        use super::super::keys::KeyPress;
        use std::hash::{SipHasher, Hash};

        let press = KeyPress::from_key_names(&["Ctrl"], "p")
            .expect("Unable to construct regular keypress");
        let press_macro = keypress!("Ctrl", "p");
        let mut hasher = SipHasher::new();
        assert!(press.hash(&mut hasher) == press_macro.hash(&mut hasher),
                "Hashes do not match");
        assert_eq!(press, press_macro);
    }
}
<|endoftext|>


<commit_before>
use crate::common::{parse_args, FileReader, read_bam_record};
use bitvec::*;
use rust_htslib::bam;
use rust_htslib::bam::Record;
use bio::alphabets::dna;
use rayon::prelude::*;

const USAGE: &str = "
Usage:
  breakfast matrix [options] <sv_file> <bam_files>...

Options:
  --threads=N         Maximum number of threads to use [default: 1]
";

// Each signature is 20+20 bp, covering both sides of the breakpoint,
// for a total of 40 bp.
#[derive(Debug)]
struct Rearrangement {
	signature: String,
	signature_revcomp: String,
	first_8_cols: String,
	//chromosome_left: String,
	//position_left: usize,
	//strand_left: char,
	//chromosome_right: String,
	//position_right: usize,
	//strand_right: char,
	//evidence: Vec<u32>
}

fn reverse_complement(seq: &str) -> String {
	String::from_utf8(dna::revcomp(seq.as_bytes())).unwrap()
}

//fn parse_strand(text: &str) -> char {
//	match text {
//		"+" => '+', "-" => '-',
//		_ => error!("Invalid strand '{}' found.", text)
//	}
//}

// This function takes the current hash as input, and modifies it according
// to the read sequence's next encoded base in the BAM file. The hash itself
// is the lower 16 bits of the u32. The upper 16 bits are used as error
// bits to indicate whether an ambiguous nucleotide was encountered.
// This way if the hash is larger than 65535, we know that the eight
// nucleotides used in the hash's calculation included some ambiguous ones.
fn hash_nucleotide(hash: u32, nuc: u8) -> u32 {
	((hash & 0b11111111_11111111_00111111_11111111u32) << 2) + match nuc {
		b'A' => 0u32, b'C' => 1u32, b'G' => 2u32, b'T' => 3u32,     // ACGT
		_ => 0b00000000_00000011_00000000_00000000u32   // Ambiguous nucleotide
	}
}

fn hash_8bp_sequence(seq: &str) -> u32 {
	assert!(seq.len() == 8);
	let mut hash: u32 = 0;
	for nuc in seq.bytes() { hash = hash_nucleotide(hash, nuc); }
	if hash & 0xFFFF0000u32 > 0 { error!("Invalid sequence '{}'.", seq); }
	hash
}

// Find the most frequent element in an unsorted vector. Operates in
// O(n log n) time.
fn most_frequent(elems: &Vec<String>) -> String {
	let mut sorted = elems.clone();
	sorted.sort_unstable();
	let mut most_frequent: usize = 0;
	let mut most_frequent_count: usize = 1;
	let mut curr_count: usize = 1;
	for k in 1..sorted.len() {
		if sorted[k] == sorted[k - 1] {
			curr_count += 1;
		} else {
			if curr_count > most_frequent_count {
				most_frequent = k - 1;
				most_frequent_count = curr_count;
			}
			curr_count = 1;
		}
	}
	if curr_count > most_frequent_count {
		most_frequent = sorted.len() - 1;
		most_frequent_count = curr_count;
	}
	sorted[most_frequent].clone()
}

fn count_rearrangements(bam_path: &str, rearrangements: &Vec<Rearrangement>)
	-> Vec<u32> {

	eprintln!("Analyzing {}...", bam_path);

	// Arrange junction signatures into a 65536-element table that is indexed
	// with the first 8 bp of the junction signature. This allows extremely
	// fast lookups.
	let mut signature_exists = bitvec![0; 65536];
	let mut signature_map: Vec<Vec<u32>> =
		(0..65536).map(|_| Vec::new()).collect();
	for r in 0..rearrangements.len() {
		// Add the signatures for the two strands into the signature map.
		let hash = hash_8bp_sequence(&rearrangements[r].signature[16..24]);
		signature_exists.set(hash as usize, true);
		signature_map[hash as usize].push(r as u32);

		let hash = hash_8bp_sequence(
			&rearrangements[r].signature_revcomp[16..24]);
		signature_exists.set(hash as usize, true);
		signature_map[hash as usize].push(r as u32);
	}

	let mut supporting_reads = vec![0; rearrangements.len()];

	let mut bam = bam::Reader::from_path(&bam_path).unwrap_or_else(
		|_| error!("Could not open BAM file."));
	let mut read = Record::new();
	while read_bam_record(&mut bam, &mut read) {
		//if !count_aligned && read.is_unmapped() == false { continue; }
		//if !count_duplicates && read.is_duplicate() { continue; }

		let seq = String::from_utf8(read.seq().as_bytes()).unwrap();

		// Start with some error bits set, so we only start checking
		// against the signature map once we have hashed at least eight
		// nucleotides.
		let mut hash = 0b00000000_00000011_00000000_00000000u32;
		'outer: for base in seq.bytes() {
			hash = hash_nucleotide(hash, base);
			if hash & 0xFFFF0000u32 > 0 { continue; }
			if signature_exists[hash as usize] == false { continue; }
			for ridx in &signature_map[hash as usize] {
				// This read contains the 4+4 bp junction signature.
				// Now check if the 20+20 bp junction is also found.
				let rearrangement = &rearrangements[*ridx as usize];
				if seq.contains(&rearrangement.signature) ||
					seq.contains(&rearrangement.signature_revcomp) {
					supporting_reads[*ridx as usize] += 1;
					break 'outer;
				}
			}
		}
	}
	return supporting_reads
}

pub fn main() {
	let args = parse_args(USAGE);
	let sv_path = args.get_str("<sv_file>");
	let bam_paths = args.get_vec("<bam_files>");
	let threads: usize = args.get_str("--threads").parse().unwrap();
	//let count_duplicates = args.get_bool("--count-duplicates");
	//let count_aligned = args.get_bool("--count-aligned");

	// Convert BAM paths to sample names
	let mut samples: Vec<String> = Vec::new();
	for s in 0..bam_paths.len() {
		let start = if let Some(slash) =
			bam_paths[s].find('/') { slash + 1 } else { 0 };
		let end = if bam_paths[s].ends_with(".bam") {
			bam_paths[s].len() - 4 } else { bam_paths[s].len() };
		samples.push(bam_paths[s][start..end].into());
	}

	let mut line = String::new();
	let mut rearrangements: Vec<Rearrangement> = Vec::new();

	// Read all rearrangement signatures into memory
	let mut skipped_ambiguous = 0;
	let mut sv_file = FileReader::new(&sv_path);
	while sv_file.read_line(&mut line) {
		if line.starts_with("CHROM\t") { continue; }
		let mut signatures: Vec<String> = Vec::new();
		let cols: Vec<&str> = line.split('\t').collect();
		if cols.len() < 9 { continue; }
		let reads: Vec<&str> = cols[8].split(';').collect();
		for read in reads {
			let pipe = read.find('|').unwrap();
			if pipe < 20 { continue; }
			signatures.push(format!("{}{}",
				&read[pipe-20..pipe], &read[pipe+1..pipe+21]));
		}

		let mut signature = most_frequent(&signatures);
		signature.make_ascii_uppercase();
		if signature.chars().any(
			|b| b != 'A' && b != 'C' && b != 'G' && b != 'T') {
			eprintln!("WARNING: Skipping the following rearrangement because its consensus signature contains ambiguous nucleotides:\n{}", line);
			skipped_ambiguous += 1;
			continue;
		}
		let signature_revcomp = reverse_complement(&signature);

		let first_8_cols = format!("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
			cols[0], cols[1], cols[2], cols[3], cols[4], cols[5],
			cols[6], cols[7]);

		rearrangements.push(Rearrangement {
			signature, signature_revcomp, first_8_cols
		});
	}
	if skipped_ambiguous > 0 {
		eprintln!("WARNING: Skipped {} rearrangements with signatures containing ambiguous nucleotides.", skipped_ambiguous);
	}

	rearrangements.sort_unstable_by(|a, b| a.signature.cmp(&b.signature));
	for k in 1..rearrangements.len() {
		if rearrangements[k - 1].signature == rearrangements[k].signature &&
			rearrangements[k - 1].first_8_cols !=
			rearrangements[k].first_8_cols {
			eprintln!("WARNING: Found two distinct rearrangements with same signature {}:\n{}\n{}\n",
				rearrangements[k].signature,
				rearrangements[k - 1].first_8_cols,
				rearrangements[k].first_8_cols);
		}
	}
	rearrangements.dedup_by(|a, b| a.signature == b.signature);

	eprintln!("Identifying supporting reads for {} rearrangements in {} BAM files...", rearrangements.len(), bam_paths.len());

	rayon::ThreadPoolBuilder::new().num_threads(threads).build_global()
		.unwrap();
	let evidence: Vec<Vec<u32>> = bam_paths.par_iter()
		.map(|bam_path| count_rearrangements(&bam_path, &rearrangements))
		.collect();

	print!("CHROM\tSTRAND\tPOSITION\tNEARBY FEATURES\t");
	print!("CHROM\tSTRAND\tPOSITION\tNEARBY FEATURES\t");
	print!("SUPPORTING READS\tSIGNATURE\tNOTES");
	for sample in &samples { print!("\t{}", sample); }
	println!();
	for r in 0..rearrangements.len() {
		print!("{}", rearrangements[r].first_8_cols);
		print!("\t\t{}|{}\t", &rearrangements[r].signature[0..20], &rearrangements[r].signature[20..]);
		for e in &evidence { print!("\t{}", e[r]); }
		println!();
	}
}

<commit_msg>Don't count mapped reads and duplicate reads.<commit_after>
use crate::common::{parse_args, FileReader, read_bam_record};
use bitvec::*;
use rust_htslib::bam;
use rust_htslib::bam::Record;
use bio::alphabets::dna;
use rayon::prelude::*;

const USAGE: &str = "
Usage:
  breakfast matrix [options] <sv_file> <bam_files>...

Options:
  --threads=N         Maximum number of threads to use [default: 1]
";

// Each signature is 20+20 bp, covering both sides of the breakpoint,
// for a total of 40 bp.
#[derive(Debug)]
struct Rearrangement {
	signature: String,
	signature_revcomp: String,
	first_8_cols: String,
	//chromosome_left: String,
	//position_left: usize,
	//strand_left: char,
	//chromosome_right: String,
	//position_right: usize,
	//strand_right: char,
	//evidence: Vec<u32>
}

fn reverse_complement(seq: &str) -> String {
	String::from_utf8(dna::revcomp(seq.as_bytes())).unwrap()
}

//fn parse_strand(text: &str) -> char {
//	match text {
//		"+" => '+', "-" => '-',
//		_ => error!("Invalid strand '{}' found.", text)
//	}
//}

// This function takes the current hash as input, and modifies it according
// to the read sequence's next encoded base in the BAM file. The hash itself
// is the lower 16 bits of the u32. The upper 16 bits are used as error
// bits to indicate whether an ambiguous nucleotide was encountered.
// This way if the hash is larger than 65535, we know that the eight
// nucleotides used in the hash's calculation included some ambiguous ones.
fn hash_nucleotide(hash: u32, nuc: u8) -> u32 {
	((hash & 0b11111111_11111111_00111111_11111111u32) << 2) + match nuc {
		b'A' => 0u32, b'C' => 1u32, b'G' => 2u32, b'T' => 3u32,     // ACGT
		_ => 0b00000000_00000011_00000000_00000000u32   // Ambiguous nucleotide
	}
}

fn hash_8bp_sequence(seq: &str) -> u32 {
	assert!(seq.len() == 8);
	let mut hash: u32 = 0;
	for nuc in seq.bytes() { hash = hash_nucleotide(hash, nuc); }
	if hash & 0xFFFF0000u32 > 0 { error!("Invalid sequence '{}'.", seq); }
	hash
}

// Find the most frequent element in an unsorted vector. Operates in
// O(n log n) time.
fn most_frequent(elems: &Vec<String>) -> String {
	let mut sorted = elems.clone();
	sorted.sort_unstable();
	let mut most_frequent: usize = 0;
	let mut most_frequent_count: usize = 1;
	let mut curr_count: usize = 1;
	for k in 1..sorted.len() {
		if sorted[k] == sorted[k - 1] {
			curr_count += 1;
		} else {
			if curr_count > most_frequent_count {
				most_frequent = k - 1;
				most_frequent_count = curr_count;
			}
			curr_count = 1;
		}
	}
	if curr_count > most_frequent_count {
		most_frequent = sorted.len() - 1;
		most_frequent_count = curr_count;
	}
	sorted[most_frequent].clone()
}

fn count_rearrangements(bam_path: &str, rearrangements: &Vec<Rearrangement>)
	-> Vec<u32> {

	eprintln!("Analyzing {}...", bam_path);

	// Arrange junction signatures into a 65536-element table that is indexed
	// with the first 8 bp of the junction signature. This allows extremely
	// fast lookups.
	let mut signature_exists = bitvec![0; 65536];
	let mut signature_map: Vec<Vec<u32>> =
		(0..65536).map(|_| Vec::new()).collect();
	for r in 0..rearrangements.len() {
		// Add the signatures for the two strands into the signature map.
		let hash = hash_8bp_sequence(&rearrangements[r].signature[16..24]);
		signature_exists.set(hash as usize, true);
		signature_map[hash as usize].push(r as u32);

		let hash = hash_8bp_sequence(
			&rearrangements[r].signature_revcomp[16..24]);
		signature_exists.set(hash as usize, true);
		signature_map[hash as usize].push(r as u32);
	}

	let mut supporting_reads = vec![0; rearrangements.len()];

	let mut bam = bam::Reader::from_path(&bam_path).unwrap_or_else(
		|_| error!("Could not open BAM file."));
	let mut read = Record::new();
	while read_bam_record(&mut bam, &mut read) {
		if read.is_unmapped() == false { continue; }
		if read.is_duplicate() { continue; }
		//if !count_aligned && read.is_unmapped() == false { continue; }
		//if !count_duplicates && read.is_duplicate() { continue; }

		let seq = String::from_utf8(read.seq().as_bytes()).unwrap();

		// Start with some error bits set, so we only start checking
		// against the signature map once we have hashed at least eight
		// nucleotides.
		let mut hash = 0b00000000_00000011_00000000_00000000u32;
		'outer: for base in seq.bytes() {
			hash = hash_nucleotide(hash, base);
			if hash & 0xFFFF0000u32 > 0 { continue; }
			if signature_exists[hash as usize] == false { continue; }
			for ridx in &signature_map[hash as usize] {
				// This read contains the 4+4 bp junction signature.
				// Now check if the 20+20 bp junction is also found.
				let rearrangement = &rearrangements[*ridx as usize];
				if seq.contains(&rearrangement.signature) ||
					seq.contains(&rearrangement.signature_revcomp) {
					supporting_reads[*ridx as usize] += 1;
					break 'outer;
				}
			}
		}
	}
	return supporting_reads
}

pub fn main() {
	let args = parse_args(USAGE);
	let sv_path = args.get_str("<sv_file>");
	let bam_paths = args.get_vec("<bam_files>");
	let threads: usize = args.get_str("--threads").parse().unwrap();
	//let count_duplicates = args.get_bool("--count-duplicates");
	//let count_aligned = args.get_bool("--count-aligned");

	// Convert BAM paths to sample names
	let mut samples: Vec<String> = Vec::new();
	for s in 0..bam_paths.len() {
		let start = if let Some(slash) =
			bam_paths[s].find('/') { slash + 1 } else { 0 };
		let end = if bam_paths[s].ends_with(".bam") {
			bam_paths[s].len() - 4 } else { bam_paths[s].len() };
		samples.push(bam_paths[s][start..end].into());
	}

	let mut line = String::new();
	let mut rearrangements: Vec<Rearrangement> = Vec::new();

	// Read all rearrangement signatures into memory
	let mut skipped_ambiguous = 0;
	let mut sv_file = FileReader::new(&sv_path);
	while sv_file.read_line(&mut line) {
		if line.starts_with("CHROM\t") { continue; }
		let mut signatures: Vec<String> = Vec::new();
		let cols: Vec<&str> = line.split('\t').collect();
		if cols.len() < 9 { continue; }
		let reads: Vec<&str> = cols[8].split(';').collect();
		for read in reads {
			let pipe = read.find('|').unwrap();
			if pipe < 20 { continue; }
			signatures.push(format!("{}{}",
				&read[pipe-20..pipe], &read[pipe+1..pipe+21]));
		}

		let mut signature = most_frequent(&signatures);
		signature.make_ascii_uppercase();
		if signature.chars().any(
			|b| b != 'A' && b != 'C' && b != 'G' && b != 'T') {
			eprintln!("WARNING: Skipping the following rearrangement because its consensus signature contains ambiguous nucleotides:\n{}", line);
			skipped_ambiguous += 1;
			continue;
		}
		let signature_revcomp = reverse_complement(&signature);

		let first_8_cols = format!("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
			cols[0], cols[1], cols[2], cols[3], cols[4], cols[5],
			cols[6], cols[7]);

		rearrangements.push(Rearrangement {
			signature, signature_revcomp, first_8_cols
		});
	}
	if skipped_ambiguous > 0 {
		eprintln!("WARNING: Skipped {} rearrangements with signatures containing ambiguous nucleotides.", skipped_ambiguous);
	}

	rearrangements.sort_unstable_by(|a, b| a.signature.cmp(&b.signature));
	for k in 1..rearrangements.len() {
		if rearrangements[k - 1].signature == rearrangements[k].signature &&
			rearrangements[k - 1].first_8_cols !=
			rearrangements[k].first_8_cols {
			eprintln!("WARNING: Found two distinct rearrangements with same signature {}:\n{}\n{}\n",
				rearrangements[k].signature,
				rearrangements[k - 1].first_8_cols,
				rearrangements[k].first_8_cols);
		}
	}
	rearrangements.dedup_by(|a, b| a.signature == b.signature);

	eprintln!("Identifying supporting reads for {} rearrangements in {} BAM files...", rearrangements.len(), bam_paths.len());

	rayon::ThreadPoolBuilder::new().num_threads(threads).build_global()
		.unwrap();
	let evidence: Vec<Vec<u32>> = bam_paths.par_iter()
		.map(|bam_path| count_rearrangements(&bam_path, &rearrangements))
		.collect();

	print!("CHROM\tSTRAND\tPOSITION\tNEARBY FEATURES\t");
	print!("CHROM\tSTRAND\tPOSITION\tNEARBY FEATURES\t");
	print!("SUPPORTING READS\tSIGNATURE\tNOTES");
	for sample in &samples { print!("\t{}", sample); }
	println!();
	for r in 0..rearrangements.len() {
		print!("{}", rearrangements[r].first_8_cols);
		print!("\t\t{}|{}\t", &rearrangements[r].signature[0..20], &rearrangements[r].signature[20..]);
		for e in &evidence { print!("\t{}", e[r]); }
		println!();
	}
}

<|endoftext|>


<commit_before>use std::fmt;

#[derive(RustcEncodable, RustcDecodable)]
pub struct Memory {
    rom: u8,
    ram_0x4000_0x7FFF: usize,
    ram_0x8000_0xBFFF: usize,
    ram_0xC000_0xFFFF: usize,

    rom0: Vec<u8>,
    rom1: Vec<u8>,
    bank: [Vec<u8>; 8],

    writable_rom: bool
}

impl Memory {
    pub fn read_word(&self, addr: u16) -> u8 {
        let mut val = 0;
        if addr <= 0x3FFF {
            match self.rom {
                0 => { val = self.rom0[addr as usize]; },
                1 => { val = self.rom1[addr as usize]; },
                _ => unreachable!()
            }
        } else if addr >= 0x4000 && addr <= 0x7FFF {
            val = self.bank[self.ram_0x4000_0x7FFF][(addr - 0x4000) as usize];
        } else if addr >= 0x8000 && addr <= 0xBFFF {
            val = self.bank[self.ram_0x8000_0xBFFF][(addr - 0x8000) as usize];
        } else if addr >= 0xC000 {
            val = self.bank[self.ram_0xC000_0xFFFF][(addr - 0xC000) as usize];
        } else {
            panic!("Trying to read from unrecognized address: {:#x}", addr);
        }

        debug!("                Read value {:#04X} from address {:#06X}", val, addr);
        val
    }

    pub fn write_word(&mut self, addr: u16, val: u8) {
        if addr >= 0xC000 {
            self.bank[self.ram_0xC000_0xFFFF][(addr - 0xC000) as usize] = val;
        } else if addr >= 0x8000 && addr <= 0xBFFF {
            self.bank[self.ram_0x8000_0xBFFF][(addr - 0x8000) as usize] = val;
        } else if addr >= 0x4000 && addr <= 0x7FFF {
            self.bank[self.ram_0x4000_0x7FFF][(addr - 0x4000) as usize] = val;
        } else {
            if self.writable_rom {
                match self.rom {
                    0 => { self.rom0[addr as usize] = val; },
                    1 => { self.rom1[addr as usize] = val; },
                    _ => unreachable!()
                }
            } else {
                panic!("Trying to write to unrecognized address: {:#x}", addr);
            }
        }

        debug!("                Write value {:#04X} to address {:#06X}", val, addr);
    }

    pub fn change_bank(&mut self, val: u8) {
        self.ram_0xC000_0xFFFF = val as usize;
    }

    pub fn change_rom_bank(&mut self, val: u8) {
        self.rom = val;
    }
}

impl fmt::Debug for Memory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "ram_0xC000_0xFFFF: {}
                     ram_0x8000_0xBFFF: {}
                     ram_0x4000_0x7FFF: {}
                     rom: {}
                    ",
                    self.ram_0xC000_0xFFFF,
                    self.ram_0x8000_0xBFFF,
                    self.ram_0x4000_0x7FFF,
                    self.rom)
    }
}

pub struct MemoryBuilder {
    rom: u8,
    ram_0x4000_0x7FFF: usize,
    ram_0x8000_0xBFFF: usize,
    ram_0xC000_0xFFFF: usize,

    rom0: Vec<u8>,
    rom1: Vec<u8>,
    bank: [Vec<u8>; 8],

    writable_rom: bool
}

impl MemoryBuilder {
    pub fn new() -> MemoryBuilder {
        MemoryBuilder {
            rom: 0,
            ram_0x4000_0x7FFF: 5,
            ram_0x8000_0xBFFF: 2,
            ram_0xC000_0xFFFF: 0,

            rom0: vec![0; 16 * 1024],
            rom1: vec![0; 16 * 1024],

            bank: [
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024]
            ],

            writable_rom: false
        }
    }

    pub fn rom0(mut self, mem: Vec<u8>) -> MemoryBuilder {
        self.rom0 = mem;
        self
    }

    pub fn rom1(mut self, mem: Vec<u8>) -> MemoryBuilder {
        self.rom1 = mem;
        self
    }

    pub fn writable_rom(mut self, val: bool) -> MemoryBuilder {
        self.writable_rom = val;
        self
    }

    pub fn finalize(self) -> Memory {
        Memory {
            rom: self.rom,
            ram_0x4000_0x7FFF: self.ram_0x4000_0x7FFF,
            ram_0x8000_0xBFFF: self.ram_0x8000_0xBFFF,
            ram_0xC000_0xFFFF: self.ram_0xC000_0xFFFF,

            rom0: self.rom0,
            rom1: self.rom1,
            bank: self.bank,

            writable_rom: self.writable_rom
        }
    }
}
<commit_msg>Refactor Memory struct to get rid of warnings<commit_after>use std::fmt;

#[derive(RustcEncodable, RustcDecodable)]
pub struct Memory {
    rom: u8,
    ram_0x4000_0x7fff: usize,
    ram_0x8000_0xbfff: usize,
    ram_0xc000_0xffff: usize,

    rom0: Vec<u8>,
    rom1: Vec<u8>,
    bank: [Vec<u8>; 8],

    writable_rom: bool
}

impl Memory {
    pub fn read_word(&self, addr: u16) -> u8 {
        let val = match addr {
            0x0000...0x3FFF => {
                match self.rom {
                    0 => self.rom0[addr as usize],
                    1 => self.rom1[addr as usize],
                    _ => unreachable!()
                }
            }
            0x4000...0x7FFF =>
                self.bank[self.ram_0x4000_0x7fff][(addr - 0x4000) as usize],
            0x8000...0xBFFF =>
                self.bank[self.ram_0x8000_0xbfff][(addr - 0x8000) as usize],
            0xC000...0xFFFF =>
                self.bank[self.ram_0xc000_0xffff][(addr - 0xC000) as usize],
            _ => unreachable!()
        };

        debug!("                Read value {:#04X} from address {:#06X}", val, addr);
        val
    }

    pub fn write_word(&mut self, addr: u16, val: u8) {
        if addr >= 0xC000 {
            self.bank[self.ram_0xc000_0xffff][(addr - 0xC000) as usize] = val;
        } else if addr >= 0x8000 && addr <= 0xBFFF {
            self.bank[self.ram_0x8000_0xbfff][(addr - 0x8000) as usize] = val;
        } else if addr >= 0x4000 && addr <= 0x7FFF {
            self.bank[self.ram_0x4000_0x7fff][(addr - 0x4000) as usize] = val;
        } else {
            if self.writable_rom {
                match self.rom {
                    0 => { self.rom0[addr as usize] = val; },
                    1 => { self.rom1[addr as usize] = val; },
                    _ => unreachable!()
                }
            } else {
                panic!("Trying to write to unrecognized address: {:#x}", addr);
            }
        }

        debug!("                Write value {:#04X} to address {:#06X}", val, addr);
    }

    pub fn change_bank(&mut self, val: u8) {
        self.ram_0xc000_0xffff = val as usize;
    }

    pub fn change_rom_bank(&mut self, val: u8) {
        self.rom = val;
    }
}

impl fmt::Debug for Memory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "ram_0xc000_0xffff: {}
                     ram_0x8000_0xbfff: {}
                     ram_0x4000_0x7fff: {}
                     rom: {}
                    ",
                    self.ram_0xc000_0xffff,
                    self.ram_0x8000_0xbfff,
                    self.ram_0x4000_0x7fff,
                    self.rom)
    }
}

pub struct MemoryBuilder {
    rom: u8,
    ram_0x4000_0x7fff: usize,
    ram_0x8000_0xbfff: usize,
    ram_0xc000_0xffff: usize,

    rom0: Vec<u8>,
    rom1: Vec<u8>,
    bank: [Vec<u8>; 8],

    writable_rom: bool
}

impl MemoryBuilder {
    pub fn new() -> MemoryBuilder {
        MemoryBuilder {
            rom: 0,
            ram_0x4000_0x7fff: 5,
            ram_0x8000_0xbfff: 2,
            ram_0xc000_0xffff: 0,

            rom0: vec![0; 16 * 1024],
            rom1: vec![0; 16 * 1024],

            bank: [
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024]
            ],

            writable_rom: false
        }
    }

    pub fn rom0(mut self, mem: Vec<u8>) -> MemoryBuilder {
        self.rom0 = mem;
        self
    }

    pub fn rom1(mut self, mem: Vec<u8>) -> MemoryBuilder {
        self.rom1 = mem;
        self
    }

    pub fn writable_rom(mut self, val: bool) -> MemoryBuilder {
        self.writable_rom = val;
        self
    }

    pub fn finalize(self) -> Memory {
        Memory {
            rom: self.rom,
            ram_0x4000_0x7fff: self.ram_0x4000_0x7fff,
            ram_0x8000_0xbfff: self.ram_0x8000_0xbfff,
            ram_0xc000_0xffff: self.ram_0xc000_0xffff,

            rom0: self.rom0,
            rom1: self.rom1,
            bank: self.bank,

            writable_rom: self.writable_rom
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Div, Neg};
use std::fmt;
use std::num::FromPrimitive;

use num::complex::{Complex, Complex64};
use num::bigint::BigInt;
use num::rational::{Ratio, BigRational};
use num::{Zero, One};

use real::{Real, int2rat, fix2rat, rat2flo};

#[derive(Clone)]
pub enum Number {
    Real(Real),
    ECmplx(Complex<BigRational>),
    ICmplx(Complex64)
}

impl fmt::Debug for Number {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Number::Real(ref r) => write!(f, "{}", r),
            &Number::ECmplx(ref c) => write!(f, "#e{}", c),
            &Number::ICmplx(ref c) => write!(f, "#i{}", c),
        }
    }
}

impl Number {
    pub fn new_int(re: isize, im: isize) -> Number {
        if im == 0 {
            Number::Real(Real::Fixnum(re))
        } else {
            let re_part = Ratio::new(
                FromPrimitive::from_int(re).unwrap(),
                One::one()
            );
            let im_part = Ratio::new(
                FromPrimitive::from_int(im).unwrap(),
                One::one()
            );
            Number::ECmplx(Complex::new(re_part, im_part))
        }
    }

    pub fn new_exact(re: (isize, isize), im: (isize, isize)) -> Number {
        let re_part = Ratio::new(
                FromPrimitive::from_int(re.0).unwrap(),
                FromPrimitive::from_int(re.1).unwrap()
        );

        let im_part = Ratio::new(
                FromPrimitive::from_int(im.0).unwrap(),
                FromPrimitive::from_int(im.1).unwrap()
        );

        if im_part.is_zero() {
            Number::Real(Real::Rational(re_part))
        } else {
            Number::ECmplx(Complex::new(re_part, im_part))
        }
    }

    pub fn new_inexact(re: f64, im: f64) -> Number {
        Number::ICmplx(Complex::new(re, im))
    }

    pub fn new_flonum(re: f64) -> Number {
        Number::Real(Real::Flonum(re))
    }

    pub fn new_imag(im: Real) -> Number {
        match im {
            Real::Flonum(i) => Number::new_inexact(0.0, i),
            _ => Number::ECmplx(Complex::new(Zero::zero(), im.to_ratio().unwrap()))
        }
    }

    pub fn new(re: Real, im: Real) -> Number {
        if re.is_exact() && im.is_exact() {
            if im.is_zero() {
                Number::Real(re)
            } else {
                Number::ECmplx(Complex::new(re.to_ratio().unwrap(), im.to_ratio().unwrap()))
            }
        } else {
            Number::new_inexact(re.to_f64(), im.to_f64())
        }
    }

    pub fn new_ratio(re: isize, im: isize) -> Number {
        let re_big = FromPrimitive::from_int(re).unwrap();
        let im_big = FromPrimitive::from_int(im).unwrap();
        Number::Real(Real::Rational(Ratio::new(re_big, im_big)).reduce())
    }

    pub fn is_exact(&self) -> bool {
        match self {
            &Number::Real(ref r) => r.is_exact(),
            &Number::ECmplx(_) => true,
            &Number::ICmplx(_) => false
        }
    }
}

impl fmt::Display for Number {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Number::Real(ref r) => write!(f, "{}", r),
            &Number::ECmplx(ref c) => write!(f, "{}", c),
            &Number::ICmplx(ref c) => write!(f, "{}", c)
        }
    }
}

impl Zero for Number {
    fn zero() -> Number {
        Number::Real(Real::Fixnum(0))
    }

    fn is_zero(&self) -> bool {
        match self {
            &Number::Real(ref r) => r.is_zero(),
            &Number::ECmplx(ref e) => e.is_zero(),
            &Number::ICmplx(ref i) => i.is_zero()
        }
    }
}

impl One for Number {
    fn one() -> Number {
        Number::Real(Real::Fixnum(1))
    }
}

impl Neg for Number {
    type Output = Number;

    fn neg(self) -> Number {
        match self {
            Number::Real(r) => Number::Real(r.neg()),
            Number::ECmplx(r) => Number::ECmplx(r.neg()),
            Number::ICmplx(r) => Number::ICmplx(r.neg())
        }
    }
}

impl<'a> Neg for &'a Number {
    type Output = Number;

    fn neg(self) -> Number {
        match self {
            &Number::Real(ref r) => Number::Real(r.neg()),
            &Number::ECmplx(ref r) => Number::ECmplx(r.neg()),
            &Number::ICmplx(ref r) => Number::ICmplx(r.neg())
        }
    }
}

impl FromPrimitive for Number {
    fn from_i64(n: i64) -> Option<Number> {
        let i: Option<BigInt> = FromPrimitive::from_i64(n);
        i.map(|n| Number::Real(Real::Integer(n).reduce()))
    }

    fn from_u64(n: u64) -> Option<Number> {
        let u: Option<BigInt> = FromPrimitive::from_u64(n);
        u.map(|n| Number::Real(Real::Integer(n).reduce()))
    }
}

pub fn inexact(n: &Complex<BigRational>) -> Complex64 {
    Complex::new(rat2flo(&n.re), rat2flo(&n.im))
}

pub fn complex(n: &Real) -> Result<Complex<BigRational>, Complex64> {
    match n {
        &Real::Fixnum(n) => Ok(Complex::new(fix2rat(n), Zero::zero())),
        &Real::Integer(ref n) => Ok(Complex::new(int2rat(n), Zero::zero())),
        &Real::Rational(ref n) => Ok(Complex::new(n.clone(), Zero::zero())),
        &Real::Flonum(f) => Err(Complex::new(f, 0.0))
    }
}

fn coerce<R, E, I, T>(lhs: &Number, rhs: &Number,
                      r_op: R, e_op: E, i_op: I)
        -> T
    where R: Fn(&Real, &Real) -> T,
          E: Fn(&Complex<BigRational>, &Complex<BigRational>) -> T,
          I: Fn(&Complex64, &Complex64) -> T
{
    match (lhs, rhs) {
        (&Number::Real(ref l), &Number::Real(ref r)) =>
            r_op(l, r),
        (&Number::Real(ref l), &Number::ECmplx(ref r)) =>
            match complex(l) {
                Ok(e) => e_op(&e, r),
                Err(i) => i_op(&i, &inexact(r))
            },
        (&Number::Real(ref l), &Number::ICmplx(ref r)) =>
            i_op(&Complex::new(l.to_f64(), Zero::zero()), r),
        (&Number::ECmplx(ref l), &Number::Real(ref r)) =>
            match complex(r) {
                Ok(e) => e_op(l, &e),
                Err(i) => i_op(&inexact(l), &i)
            },
        (&Number::ECmplx(ref l), &Number::ECmplx(ref r)) =>
            e_op(l, r),
        (&Number::ECmplx(ref l), &Number::ICmplx(ref r)) =>
            i_op(&inexact(l), r),
        (&Number::ICmplx(ref l), &Number::Real(ref r)) =>
            i_op(l, &Complex::new(r.to_f64(), Zero::zero())),
        (&Number::ICmplx(ref l), &Number::ECmplx(ref r)) =>
            i_op(l, &inexact(r)),
        (&Number::ICmplx(ref l), &Number::ICmplx(ref r)) =>
            i_op(l, r)
    }
}

fn coerce_arith<R, E, I>(lhs: &Number, rhs: &Number,
                         r_op: R, e_op: E, i_op: I)
        -> Number
    where R: Fn(&Real, &Real) -> Real,
          E: Fn(&Complex<BigRational>, &Complex<BigRational>) -> Complex<BigRational>,
          I: Fn(&Complex64, &Complex64) -> Complex64
{
    coerce(lhs, rhs,
           |x, y| Number::Real(r_op(x, y)),
           |x, y| Number::ECmplx(e_op(x, y)),
           |x, y| Number::ICmplx(i_op(x, y))
    )
}

impl PartialEq for Number {
    fn eq(&self, other: &Number) -> bool {
        coerce(self, other,
               |x, y| x == y,
               |x, y| x == y,
               |x, y| x == y
        )
    }
}

macro_rules! impl_arith {
    ($tr:ident, $op:ident) => {
        impl $tr<Number> for Number {
            type Output = Number;

            fn $op(self, other: Number) -> Number {
                coerce_arith(&self, &other,
                             |x, y| x.$op(y),
                             |x, y| x.$op(y),
                             |x, y| x.$op(y)
                )
            }
        }

        impl<'a, 'b> $tr<&'a Number> for &'b Number {
            type Output = Number;

            fn $op(self, other: &Number) -> Number {
                coerce_arith(self, other,
                             |x, y| x.$op(y),
                             |x, y| x.$op(y),
                             |x, y| x.$op(y)
                )
            }
        }
    }
}

impl_arith!(Add, add);
impl_arith!(Sub, sub);
impl_arith!(Mul, mul);
impl_arith!(Div, div);

#[cfg(test)]
mod test {
    use super::Number;
    use real::Real;

    #[test]
    fn test_eq() {
        let cmplx = Number::new_int(1, 0);
        let fixnum = Number::Real(Real::Fixnum(1));
        assert!(cmplx == fixnum);
    }

    #[test]
    fn test_add() {
        let cmplx11 = Number::new_int(1, 1);
        let fixnum = Number::Real(Real::Fixnum(1));
        let cmplx21 = Number::new_int(2, 1);
        assert_eq!(cmplx21, fixnum + cmplx11);
    }

    #[test]
    fn test_sub() {
        let cmplx31 = Number::new_inexact(3.0, 1.0);
        let fixnum = Number::Real(Real::Fixnum(2));
        let cmplx11 = Number::new_inexact(1.0, 1.0);
        assert_eq!(cmplx11, cmplx31 - fixnum);
    }

    #[test]
    fn test_mul() {
        let cmplx21 = Number::new_int(2, 1);
        let cmplx31 = Number::new_int(3, 1);
        let cmplx55 = Number::new_int(5, 5);
        assert_eq!(cmplx55, cmplx21 * cmplx31);
    }

    #[test]
    fn test_div() {
        let cmplx21 = Number::new_inexact(2.0, 1.0);
        let cmplx31 = Number::new_int(3, 1);
        let cmplx55 = Number::new_inexact(5.0, 5.0);
        assert_eq!(cmplx21, cmplx55 / cmplx31);
    }
}
<commit_msg>Reduce exact complex with zero imaginary part<commit_after>use std::ops::{Add, Sub, Mul, Div, Neg};
use std::fmt;
use std::num::FromPrimitive;

use num::complex::{Complex, Complex64};
use num::bigint::BigInt;
use num::rational::{Ratio, BigRational};
use num::{Zero, One};

use real::{Real, int2rat, fix2rat, rat2flo};

#[derive(Clone)]
pub enum Number {
    Real(Real),
    ECmplx(Complex<BigRational>),
    ICmplx(Complex64)
}

impl fmt::Debug for Number {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Number::Real(ref r) => write!(f, "{}", r),
            &Number::ECmplx(ref c) => write!(f, "#e{}", c),
            &Number::ICmplx(ref c) => write!(f, "#i{}", c),
        }
    }
}

impl Number {
    pub fn new_int(re: isize, im: isize) -> Number {
        if im == 0 {
            Number::Real(Real::Fixnum(re))
        } else {
            let re_part = Ratio::new(
                FromPrimitive::from_int(re).unwrap(),
                One::one()
            );
            let im_part = Ratio::new(
                FromPrimitive::from_int(im).unwrap(),
                One::one()
            );
            Number::ECmplx(Complex::new(re_part, im_part))
        }
    }

    pub fn new_exact(re: (isize, isize), im: (isize, isize)) -> Number {
        let re_part = Ratio::new(
                FromPrimitive::from_int(re.0).unwrap(),
                FromPrimitive::from_int(re.1).unwrap()
        );

        let im_part = Ratio::new(
                FromPrimitive::from_int(im.0).unwrap(),
                FromPrimitive::from_int(im.1).unwrap()
        );

        if im_part.is_zero() {
            Number::Real(Real::Rational(re_part))
        } else {
            Number::ECmplx(Complex::new(re_part, im_part))
        }
    }

    pub fn new_inexact(re: f64, im: f64) -> Number {
        Number::ICmplx(Complex::new(re, im))
    }

    pub fn new_flonum(re: f64) -> Number {
        Number::Real(Real::Flonum(re))
    }

    pub fn new_imag(im: Real) -> Number {
        match im {
            Real::Flonum(i) => Number::new_inexact(0.0, i),
            _ => Number::ECmplx(Complex::new(Zero::zero(), im.to_ratio().unwrap()))
        }
    }

    pub fn new(re: Real, im: Real) -> Number {
        if re.is_exact() && im.is_exact() {
            if im.is_zero() {
                Number::Real(re)
            } else {
                Number::ECmplx(Complex::new(re.to_ratio().unwrap(), im.to_ratio().unwrap()))
            }
        } else {
            Number::new_inexact(re.to_f64(), im.to_f64())
        }
    }

    pub fn new_ratio(re: isize, im: isize) -> Number {
        let re_big = FromPrimitive::from_int(re).unwrap();
        let im_big = FromPrimitive::from_int(im).unwrap();
        Number::Real(Real::Rational(Ratio::new(re_big, im_big)).reduce())
    }

    pub fn is_exact(&self) -> bool {
        match self {
            &Number::Real(ref r) => r.is_exact(),
            &Number::ECmplx(_) => true,
            &Number::ICmplx(_) => false
        }
    }
}

impl fmt::Display for Number {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Number::Real(ref r) => write!(f, "{}", r),
            &Number::ECmplx(ref c) => write!(f, "{}", c),
            &Number::ICmplx(ref c) => write!(f, "{}", c)
        }
    }
}

impl Zero for Number {
    fn zero() -> Number {
        Number::Real(Real::Fixnum(0))
    }

    fn is_zero(&self) -> bool {
        match self {
            &Number::Real(ref r) => r.is_zero(),
            &Number::ECmplx(ref e) => e.is_zero(),
            &Number::ICmplx(ref i) => i.is_zero()
        }
    }
}

impl One for Number {
    fn one() -> Number {
        Number::Real(Real::Fixnum(1))
    }
}

impl Neg for Number {
    type Output = Number;

    fn neg(self) -> Number {
        match self {
            Number::Real(r) => Number::Real(r.neg()),
            Number::ECmplx(r) => Number::ECmplx(r.neg()),
            Number::ICmplx(r) => Number::ICmplx(r.neg())
        }
    }
}

impl<'a> Neg for &'a Number {
    type Output = Number;

    fn neg(self) -> Number {
        match self {
            &Number::Real(ref r) => Number::Real(r.neg()),
            &Number::ECmplx(ref r) => Number::ECmplx(r.neg()),
            &Number::ICmplx(ref r) => Number::ICmplx(r.neg())
        }
    }
}

impl FromPrimitive for Number {
    fn from_i64(n: i64) -> Option<Number> {
        let i: Option<BigInt> = FromPrimitive::from_i64(n);
        i.map(|n| Number::Real(Real::Integer(n).reduce()))
    }

    fn from_u64(n: u64) -> Option<Number> {
        let u: Option<BigInt> = FromPrimitive::from_u64(n);
        u.map(|n| Number::Real(Real::Integer(n).reduce()))
    }
}

pub fn inexact(n: &Complex<BigRational>) -> Complex64 {
    Complex::new(rat2flo(&n.re), rat2flo(&n.im))
}

pub fn complex(n: &Real) -> Result<Complex<BigRational>, Complex64> {
    match n {
        &Real::Fixnum(n) => Ok(Complex::new(fix2rat(n), Zero::zero())),
        &Real::Integer(ref n) => Ok(Complex::new(int2rat(n), Zero::zero())),
        &Real::Rational(ref n) => Ok(Complex::new(n.clone(), Zero::zero())),
        &Real::Flonum(f) => Err(Complex::new(f, 0.0))
    }
}

fn coerce<R, E, I, T>(lhs: &Number, rhs: &Number,
                      r_op: R, e_op: E, i_op: I)
        -> T
    where R: Fn(&Real, &Real) -> T,
          E: Fn(&Complex<BigRational>, &Complex<BigRational>) -> T,
          I: Fn(&Complex64, &Complex64) -> T
{
    match (lhs, rhs) {
        (&Number::Real(ref l), &Number::Real(ref r)) =>
            r_op(l, r),
        (&Number::Real(ref l), &Number::ECmplx(ref r)) =>
            match complex(l) {
                Ok(e) => e_op(&e, r),
                Err(i) => i_op(&i, &inexact(r))
            },
        (&Number::Real(ref l), &Number::ICmplx(ref r)) =>
            i_op(&Complex::new(l.to_f64(), Zero::zero()), r),
        (&Number::ECmplx(ref l), &Number::Real(ref r)) =>
            match complex(r) {
                Ok(e) => e_op(l, &e),
                Err(i) => i_op(&inexact(l), &i)
            },
        (&Number::ECmplx(ref l), &Number::ECmplx(ref r)) =>
            e_op(l, r),
        (&Number::ECmplx(ref l), &Number::ICmplx(ref r)) =>
            i_op(&inexact(l), r),
        (&Number::ICmplx(ref l), &Number::Real(ref r)) =>
            i_op(l, &Complex::new(r.to_f64(), Zero::zero())),
        (&Number::ICmplx(ref l), &Number::ECmplx(ref r)) =>
            i_op(l, &inexact(r)),
        (&Number::ICmplx(ref l), &Number::ICmplx(ref r)) =>
            i_op(l, r)
    }
}

fn coerce_arith<R, E, I>(lhs: &Number, rhs: &Number,
                         r_op: R, e_op: E, i_op: I)
        -> Number
    where R: Fn(&Real, &Real) -> Real,
          E: Fn(&Complex<BigRational>, &Complex<BigRational>) -> Complex<BigRational>,
          I: Fn(&Complex64, &Complex64) -> Complex64
{
    coerce(lhs, rhs,
           |x, y| Number::Real(r_op(x, y)),
           |x, y| {
               let res = e_op(x, y);
               if res.im.is_zero() {
                   Number::Real(Real::Rational(res.re).reduce())
               } else {
                   Number::ECmplx(res)
               }
           },
           |x, y| Number::ICmplx(i_op(x, y))
    )
}

impl PartialEq for Number {
    fn eq(&self, other: &Number) -> bool {
        coerce(self, other,
               |x, y| x == y,
               |x, y| x == y,
               |x, y| x == y
        )
    }
}

macro_rules! impl_arith {
    ($tr:ident, $op:ident) => {
        impl $tr<Number> for Number {
            type Output = Number;

            fn $op(self, other: Number) -> Number {
                coerce_arith(&self, &other,
                             |x, y| x.$op(y),
                             |x, y| x.$op(y),
                             |x, y| x.$op(y)
                )
            }
        }

        impl<'a, 'b> $tr<&'a Number> for &'b Number {
            type Output = Number;

            fn $op(self, other: &Number) -> Number {
                coerce_arith(self, other,
                             |x, y| x.$op(y),
                             |x, y| x.$op(y),
                             |x, y| x.$op(y)
                )
            }
        }
    }
}

impl_arith!(Add, add);
impl_arith!(Sub, sub);
impl_arith!(Mul, mul);
impl_arith!(Div, div);

#[cfg(test)]
mod test {
    use super::Number;
    use real::Real;

    #[test]
    fn test_eq() {
        let cmplx = Number::new_int(1, 0);
        let fixnum = Number::Real(Real::Fixnum(1));
        assert!(cmplx == fixnum);
    }

    #[test]
    fn test_add() {
        let cmplx11 = Number::new_int(1, 1);
        let fixnum = Number::Real(Real::Fixnum(1));
        let cmplx21 = Number::new_int(2, 1);
        assert_eq!(cmplx21, fixnum + cmplx11);
    }

    #[test]
    fn test_sub() {
        let cmplx31 = Number::new_inexact(3.0, 1.0);
        let fixnum = Number::Real(Real::Fixnum(2));
        let cmplx11 = Number::new_inexact(1.0, 1.0);
        assert_eq!(cmplx11, cmplx31 - fixnum);
    }

    #[test]
    fn test_mul() {
        let cmplx21 = Number::new_int(2, 1);
        let cmplx31 = Number::new_int(3, 1);
        let cmplx55 = Number::new_int(5, 5);
        assert_eq!(cmplx55, cmplx21 * cmplx31);
    }

    #[test]
    fn test_div() {
        let cmplx21 = Number::new_inexact(2.0, 1.0);
        let cmplx31 = Number::new_int(3, 1);
        let cmplx55 = Number::new_inexact(5.0, 5.0);
        assert_eq!(cmplx21, cmplx55 / cmplx31);
    }
}
<|endoftext|>