FEAT: Add StableGraph::filter_map

Add helper methods to add new "tombstone" nodes/edges, so that we
reproduce the original node / edge indices exactly. We put the regular
free lists to side for this and keep it separately, so that add
node/edge don't reuse them during the mapping.
diff --git a/src/graph_impl/stable_graph/mod.rs b/src/graph_impl/stable_graph/mod.rs
index c776f6c..29f1edf 100644
--- a/src/graph_impl/stable_graph/mod.rs
+++ b/src/graph_impl/stable_graph/mod.rs
@@ -248,6 +248,15 @@
         index
     }
 
+    /// free_node: Which free list to update for the vacancy
+    fn add_vacant_node(&mut self, free_node: &mut NodeIndex<Ix>) {
+        let node_idx = self.g.add_node(None);
+        // link the free list
+        let node_slot = &mut self.g.nodes[node_idx.index()];
+        node_slot.next[0] = free_node._into_edge();
+        *free_node = node_idx;
+    }
+
     /// Remove `a` from the graph if it exists, and return its weight.
     /// If it doesn't exist in the graph, return `None`.
     ///
@@ -376,6 +385,20 @@
         edge_idx
     }
 
+    /// free_edge: Which free list to update for the vacancy
+    fn add_vacant_edge(&mut self, free_edge: &mut EdgeIndex<Ix>) {
+        let edge_idx = EdgeIndex::new(self.g.edges.len());
+        debug_assert!(edge_idx != EdgeIndex::end());
+        let mut edge = Edge {
+            weight: None,
+            node: [NodeIndex::end(); 2],
+            next: [EdgeIndex::end(); 2],
+        };
+        edge.next[0] = *free_edge;
+        *free_edge = edge_idx;
+        self.g.edges.push(edge);
+    }
+
     /// Add or update an edge from `a` to `b`.
     /// If the edge already exists, its weight is updated.
     ///
@@ -738,6 +761,50 @@
         }
     }
 
+    pub fn filter_map<'a, F, G, N2, E2>(&'a self, mut node_map: F, mut edge_map: G)
+        -> StableGraph<N2, E2, Ty, Ix>
+        where F: FnMut(NodeIndex<Ix>, &'a N) -> Option<N2>,
+              G: FnMut(EdgeIndex<Ix>, &'a E) -> Option<E2>,
+    {
+        let node_bound = self.node_bound();
+        let edge_bound = self.edge_bound();
+        let mut result_g = StableGraph::with_capacity(node_bound, edge_bound);
+        // use separate free lists so that
+        // add_node / add_edge below do not reuse the tombstones
+        let mut free_node = NodeIndex::end();
+        let mut free_edge = EdgeIndex::end();
+
+        // the stable graph keeps the node map itself
+
+        for (i, node) in enumerate(self.raw_nodes()) {
+            if i >= node_bound { break; }
+            if let Some(node_weight) = node.weight.as_ref() {
+                if let Some(new_weight) = node_map(NodeIndex::new(i), node_weight) {
+                    result_g.add_node(new_weight);
+                    continue;
+                }
+            }
+            result_g.add_vacant_node(&mut free_node);
+        }
+        for (i, edge) in enumerate(self.raw_edges()) {
+            if i >= edge_bound { break; }
+            let source = edge.source();
+            let target = edge.target();
+            if let Some(edge_weight) = edge.weight.as_ref() {
+                if result_g.contains_node(source) && result_g.contains_node(target) {
+                    if let Some(new_weight) = edge_map(EdgeIndex::new(i), edge_weight) {
+                        result_g.add_edge(source, target, new_weight);
+                        continue;
+                    }
+                }
+            }
+            result_g.add_vacant_edge(&mut free_edge);
+        }
+        result_g.free_node = free_node;
+        result_g.free_edge = free_edge;
+        result_g.check_free_lists();
+        result_g
+    }
 
     /// Extend the graph from an iterable of edges.
     ///
@@ -772,13 +839,10 @@
         self.g.raw_nodes()
     }
 
-    // used by check_free_lists conditionally
-    #[allow(unused)]
     fn raw_edges(&self) -> &[Edge<Option<E>, Ix>] {
         self.g.raw_edges()
     }
 
-    #[cfg(feature = "serde-1")]
     fn edge_bound(&self) -> usize {
         self.edge_references()
             .next_back()
diff --git a/tests/quickcheck.rs b/tests/quickcheck.rs
index 43b2545..2620c09 100644
--- a/tests/quickcheck.rs
+++ b/tests/quickcheck.rs
@@ -806,4 +806,32 @@
             gr2.edge_references().map(|ed| (ed.id(), ed.source().index(), ed.target().index()))
         );
     }
+
+    fn stable_di_graph_map_id(gr1: StableDiGraph<usize, usize>) -> () {
+        let gr2 = gr1.map(|_, &nw| nw, |_, &ew| ew);
+        assert!(nodes_eq!(gr1, gr2));
+        assert!(edgew_eq!(gr1, gr2));
+        assert!(edges_eq!(gr1, gr2));
+    }
+
+    fn stable_un_graph_map_id(gr1: StableUnGraph<usize, usize>) -> () {
+        let gr2 = gr1.map(|_, &nw| nw, |_, &ew| ew);
+        assert!(nodes_eq!(gr1, gr2));
+        assert!(edgew_eq!(gr1, gr2));
+        assert!(edges_eq!(gr1, gr2));
+    }
+
+    fn stable_di_graph_filter_map_id(gr1: StableDiGraph<usize, usize>) -> () {
+        let gr2 = gr1.filter_map(|_, &nw| Some(nw), |_, &ew| Some(ew));
+        assert!(nodes_eq!(gr1, gr2));
+        assert!(edgew_eq!(gr1, gr2));
+        assert!(edges_eq!(gr1, gr2));
+    }
+
+    fn test_stable_un_graph_filter_map_id(gr1: StableUnGraph<usize, usize>) -> () {
+        let gr2 = gr1.filter_map(|_, &nw| Some(nw), |_, &ew| Some(ew));
+        assert!(nodes_eq!(gr1, gr2));
+        assert!(edgew_eq!(gr1, gr2));
+        assert!(edges_eq!(gr1, gr2));
+    }
 }