Added the view module and a few basic tests.
This commit is contained in:
parent
50bdbb41a7
commit
154e49c9f0
@ -5,6 +5,7 @@ authors = ["Stu Black"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
r4 = "1.0"
|
||||
symbol-map = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
|
45
src/lib.rs
45
src/lib.rs
@ -2,6 +2,7 @@ pub(crate) mod base;
|
||||
pub mod mutators;
|
||||
pub mod nav;
|
||||
pub mod search;
|
||||
pub mod view;
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::error::Error;
|
||||
@ -29,12 +30,9 @@ use symbol_map::SymbolId;
|
||||
/// - `A`: The type of graph edge data.
|
||||
///
|
||||
/// Vertices are addressed by content. To examine graph contents, obtain a node
|
||||
/// handle with `get_node`. To modify graph contents, add new root vertices with
|
||||
/// `add_node` and retrieve extant vertices with `get_node_mut`.
|
||||
pub struct Graph<T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone,
|
||||
{
|
||||
/// handle with `find_node`. To modify graph contents, add new root vertices with
|
||||
/// `add_node` and retrieve extant vertices with `find_node_mut`.
|
||||
pub struct Graph<T: Hash + Eq + Clone, S, A> {
|
||||
/// Lookup table that maps from game states to `VertexId`.
|
||||
state_ids: symbol_map::indexing::HashIndexing<T, VertexId>,
|
||||
vertices: Vec<RawVertex<S>>, // Indexed by VertexId.
|
||||
@ -110,7 +108,7 @@ where
|
||||
/// Gets a node handle for the given game state.
|
||||
///
|
||||
/// If `state` does not correspond to a known game state, returns `None`.
|
||||
pub fn get_node<'s>(&'s self, state: &T) -> Option<Node<'s, T, S, A>> {
|
||||
pub fn find_node<'s>(&'s self, state: &T) -> Option<Node<'s, T, S, A>> {
|
||||
match self.state_ids.get(state) {
|
||||
Some(symbol) => Some(Node::new(self, *symbol.id())),
|
||||
None => None,
|
||||
@ -120,7 +118,7 @@ where
|
||||
/// Gets a mutable node handle for the given game state.
|
||||
///
|
||||
/// If `state` does not correspond to a known game state, returns `None`.
|
||||
pub fn get_node_mut<'s>(&'s mut self, state: &T) -> Option<MutNode<'s, T, S, A>> {
|
||||
pub fn find_node_mut<'s>(&'s mut self, state: &T) -> Option<MutNode<'s, T, S, A>> {
|
||||
match self.state_ids.get(state).map(|s| s.id().clone()) {
|
||||
Some(id) => Some(MutNode::new(self, id)),
|
||||
None => None,
|
||||
@ -195,27 +193,6 @@ where
|
||||
// TODO: This is actually the number of edges we have allocated.
|
||||
self.arcs.len()
|
||||
}
|
||||
|
||||
/// Deletes all graph components that are not reachable by traversal
|
||||
/// starting from each vertex corresponding to the game states in `roots`.
|
||||
///
|
||||
/// Game states in `roots` which do not have a corresponding vertex are
|
||||
/// ignored.
|
||||
pub fn retain_reachable_from(&mut self, roots: &[&T]) {
|
||||
let mut root_ids = Vec::with_capacity(roots.len());
|
||||
for state in roots.iter() {
|
||||
if let Some(symbol) = self.state_ids.get(state) {
|
||||
root_ids.push(*symbol.id());
|
||||
}
|
||||
}
|
||||
self.retain_reachable_from_ids(&root_ids);
|
||||
}
|
||||
|
||||
/// As `retain_reachable_from`, but working over raw `VertexId`s instead of
|
||||
/// root data.
|
||||
fn retain_reachable_from_ids(&mut self, root_ids: &[VertexId]) {
|
||||
mutators::mark_compact::Collector::retain_reachable(self, root_ids);
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows both read-only references into a `Graph` and operations that modify
|
||||
@ -239,7 +216,7 @@ where
|
||||
/// let root1 = appendable.append_node(0, "data1".to_string());
|
||||
/// // If appendable were a Graph, we could not call append_node while root1 is alive.
|
||||
/// let root2 = appendable.append_node(1, "data2".to_string());
|
||||
/// assert_eq!("data1", appendable.get_node(&0).unwrap().get_data());
|
||||
/// assert_eq!("data1", appendable.find_node(&0).unwrap().get_data());
|
||||
/// assert!(root1.is_leaf());
|
||||
/// let edge = appendable.append_edge(root1.clone(), root2.clone(), 3.3).unwrap();
|
||||
/// assert_eq!(*edge.get_source().get_label(), 0);
|
||||
@ -346,9 +323,9 @@ mod test {
|
||||
let graph = Arc::new(g);
|
||||
thread::scope(move |s| {
|
||||
let g = graph.clone();
|
||||
let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
|
||||
let t1 = s.spawn(move |_| g.find_node(&"root").map(|n| n.get_id()));
|
||||
let g = graph.clone();
|
||||
let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
|
||||
let t2 = s.spawn(move |_| g.find_node(&"1").map(|n| n.get_id()));
|
||||
match t1.join() {
|
||||
Ok(Some(id)) => assert_eq!(id, 0),
|
||||
_ => panic!(),
|
||||
@ -368,8 +345,8 @@ mod test {
|
||||
g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
|
||||
let g = &g;
|
||||
thread::scope(|s| {
|
||||
let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
|
||||
let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
|
||||
let t1 = s.spawn(move |_| g.find_node(&"root").map(|n| n.get_id()));
|
||||
let t2 = s.spawn(move |_| g.find_node(&"1").map(|n| n.get_id()));
|
||||
match t1.join() {
|
||||
Ok(Some(id)) => assert_eq!(id, 0),
|
||||
_ => panic!(),
|
||||
|
@ -11,7 +11,9 @@ use std::hash::Hash;
|
||||
|
||||
use crate::base::{EdgeId, RawEdge, RawVertex, VertexId};
|
||||
use crate::nav::{ChildList, ChildListIter, Edge, Node, ParentList, ParentListIter};
|
||||
use crate::view;
|
||||
use crate::Graph;
|
||||
use r4::iterate;
|
||||
use symbol_map::indexing::{Indexing, Insertion};
|
||||
use symbol_map::SymbolId;
|
||||
|
||||
@ -25,22 +27,12 @@ pub(crate) mod mark_compact;
|
||||
/// It enables local graph mutation, whether via mutation of vertex data or
|
||||
/// mutation of graph topology (adding edges). Edges may be added
|
||||
/// using the handle returned by `get_child_adder` or `to_child_adder`.
|
||||
pub struct MutNode<'a, T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone + 'a,
|
||||
S: 'a,
|
||||
A: 'a,
|
||||
{
|
||||
pub struct MutNode<'a, T: Hash + Eq + Clone + 'a, S: 'a, A: 'a> {
|
||||
pub(crate) graph: &'a mut Graph<T, S, A>,
|
||||
pub(crate) id: VertexId,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> MutNode<'a, T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone + 'a,
|
||||
S: 'a,
|
||||
A: 'a,
|
||||
{
|
||||
impl<'a, T: Hash + Eq + Clone + 'a, S: 'a, A: 'a> MutNode<'a, T, S, A> {
|
||||
/// Creates a new `MutNode` for the given graph and gamestate. This method is
|
||||
/// not exported by the crate because it exposes implementation details.
|
||||
pub(crate) fn new(graph: &'a mut Graph<T, S, A>, id: VertexId) -> Self {
|
||||
@ -155,29 +147,24 @@ where
|
||||
|
||||
/// Prunes the underlying graph by removing components not reachable from
|
||||
/// this node.
|
||||
pub fn retain_reachable(&mut self) {
|
||||
self.graph.retain_reachable_from_ids(&[self.id]);
|
||||
self.id = VertexId(0);
|
||||
pub fn retain_reachable(self) -> MutNode<'a, T, S, A>{
|
||||
MutNode {
|
||||
id: VertexId(0),
|
||||
graph: view::of_node(self, |mut v, n| {
|
||||
v.retain_reachable_from(iterate!(yield n));
|
||||
v.into()
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A traversible list of a vertex's outgoing edges.
|
||||
pub struct MutChildList<'a, T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone + 'a,
|
||||
S: 'a,
|
||||
A: 'a,
|
||||
{
|
||||
pub struct MutChildList<'a, T: Hash + Eq + Clone + 'a, S: 'a, A: 'a> {
|
||||
graph: &'a mut Graph<T, S, A>,
|
||||
id: VertexId,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> MutChildList<'a, T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone + 'a,
|
||||
S: 'a,
|
||||
A: 'a,
|
||||
{
|
||||
impl<'a, T: Hash + Eq + Clone + 'a, S: 'a, A: 'a> MutChildList<'a, T, S, A> {
|
||||
fn vertex<'s>(&'s self) -> &'s RawVertex<S> {
|
||||
self.graph.get_vertex(self.id)
|
||||
}
|
||||
@ -302,22 +289,12 @@ where
|
||||
}
|
||||
|
||||
/// A traversible list of a vertex's incoming edges.
|
||||
pub struct MutParentList<'a, T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone + 'a,
|
||||
S: 'a,
|
||||
A: 'a,
|
||||
{
|
||||
pub struct MutParentList<'a, T: Hash + Eq + Clone + 'a, S: 'a, A: 'a> {
|
||||
graph: &'a mut Graph<T, S, A>,
|
||||
id: VertexId,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> MutParentList<'a, T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone + 'a,
|
||||
S: 'a,
|
||||
A: 'a,
|
||||
{
|
||||
impl<'a, T: Hash + Eq + Clone + 'a, S: 'a, A: 'a> MutParentList<'a, T, S, A> {
|
||||
fn vertex<'s>(&'s self) -> &'s RawVertex<S> {
|
||||
self.graph.get_vertex(self.id)
|
||||
}
|
||||
@ -457,22 +434,12 @@ where
|
||||
/// mutation of graph topology (adding vertices). Vertices may be added to
|
||||
/// unexpanded edges using the handle returned by `get_target_mut` or
|
||||
/// `to_target`.
|
||||
pub struct MutEdge<'a, T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone + 'a,
|
||||
S: 'a,
|
||||
A: 'a,
|
||||
{
|
||||
graph: &'a mut Graph<T, S, A>,
|
||||
id: EdgeId,
|
||||
pub struct MutEdge<'a, T: Hash + Eq + Clone + 'a, S: 'a, A: 'a> {
|
||||
pub(crate) graph: &'a mut Graph<T, S, A>,
|
||||
pub(crate) id: EdgeId,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> MutEdge<'a, T, S, A>
|
||||
where
|
||||
T: Hash + Eq + Clone + 'a,
|
||||
S: 'a,
|
||||
A: 'a,
|
||||
{
|
||||
impl<'a, T: Hash + Eq + Clone + 'a, S: 'a, A: 'a> MutEdge<'a, T, S, A> {
|
||||
/// Creates a new `MutEdge` for the given graph and gamestate. This method is
|
||||
/// not exported by the crate because it exposes implementation details.
|
||||
pub(crate) fn new(graph: &'a mut Graph<T, S, A>, id: EdgeId) -> Self {
|
||||
|
@ -69,8 +69,7 @@ where
|
||||
&self.graph.get_vertex(self.id).data
|
||||
}
|
||||
|
||||
/// Returns true iff this vertex has no outgoing edges (regardless of
|
||||
/// whether they are expanded).
|
||||
/// Returns true iff this vertex has no outgoing edges.
|
||||
pub fn is_leaf(&self) -> bool {
|
||||
self.children().is_empty()
|
||||
}
|
||||
@ -380,8 +379,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the target of this edge. If the edge is unexpanded, no data will
|
||||
/// be available. If it is expanded, a node handle will be available.
|
||||
/// Returns the target of this edge.
|
||||
pub fn get_target(&self) -> Node<'a, T, S, A> {
|
||||
Node {
|
||||
graph: self.graph,
|
||||
|
@ -420,7 +420,7 @@ mod test {
|
||||
Ok(Some(Traversal::Child(1)))
|
||||
}
|
||||
|
||||
let mut path = Stack::new(g.get_node_mut(&"A").unwrap());
|
||||
let mut path = Stack::new(g.find_node_mut(&"A").unwrap());
|
||||
assert_eq!(1, path.len());
|
||||
|
||||
match path.push(traverse_second_child) {
|
||||
@ -464,7 +464,7 @@ mod test {
|
||||
Err(MockError(()))
|
||||
}
|
||||
|
||||
let mut path = Stack::new(g.get_node_mut(&"A").unwrap());
|
||||
let mut path = Stack::new(g.find_node_mut(&"A").unwrap());
|
||||
assert_eq!(1, path.len());
|
||||
|
||||
match path.push(traverse_err) {
|
||||
@ -544,7 +544,7 @@ mod test {
|
||||
Ok(Some(Traversal::Child(1)))
|
||||
}
|
||||
|
||||
let mut path = Stack::new(g.get_node_mut(&"A").unwrap());
|
||||
let mut path = Stack::new(g.find_node_mut(&"A").unwrap());
|
||||
assert_eq!(1, path.len());
|
||||
|
||||
match path.push(traverse_second_child) {
|
||||
@ -619,7 +619,7 @@ mod test {
|
||||
Err(MockError(()))
|
||||
}
|
||||
|
||||
let mut path = Stack::new(g.get_node_mut(&"A").unwrap());
|
||||
let mut path = Stack::new(g.find_node_mut(&"A").unwrap());
|
||||
assert_eq!(1, path.len());
|
||||
|
||||
match path.push(traverse_err) {
|
||||
@ -659,7 +659,7 @@ mod test {
|
||||
Ok(Some(Traversal::Child(0)))
|
||||
}
|
||||
|
||||
let mut path = Stack::new(g.get_node_mut(&"root").unwrap());
|
||||
let mut path = Stack::new(g.find_node_mut(&"root").unwrap());
|
||||
match path.push(traverse_first_child) {
|
||||
Ok(Some(e)) => assert_eq!("root", *e.get_source().get_data()),
|
||||
_ => panic!(),
|
||||
@ -716,7 +716,7 @@ mod test {
|
||||
let mut g = Graph::new();
|
||||
add_edge(&mut g, "root", "A");
|
||||
|
||||
let mut path = Stack::new(g.get_node_mut(&"root").unwrap());
|
||||
let mut path = Stack::new(g.find_node_mut(&"root").unwrap());
|
||||
assert_eq!(1, path.len());
|
||||
|
||||
fn traverse_first_child<'a>(n: &Node<'a>) -> Result<Option<Traversal>, MockError> {
|
||||
@ -746,7 +746,7 @@ mod test {
|
||||
let mut g = Graph::new();
|
||||
add_edge(&mut g, "root", "A");
|
||||
|
||||
let path = Stack::new(g.get_node_mut(&"root").unwrap());
|
||||
let path = Stack::new(g.find_node_mut(&"root").unwrap());
|
||||
assert_eq!(1, path.len());
|
||||
|
||||
assert_eq!("root", *path.to_head().get_data());
|
||||
@ -757,7 +757,7 @@ mod test {
|
||||
let mut g = Graph::new();
|
||||
add_edge(&mut g, "root", "A");
|
||||
|
||||
let mut path = Stack::new(g.get_node_mut(&"root").unwrap());
|
||||
let mut path = Stack::new(g.find_node_mut(&"root").unwrap());
|
||||
assert_eq!(1, path.len());
|
||||
|
||||
fn traverse_first_child<'a>(n: &Node<'a>) -> Result<Option<Traversal>, MockError> {
|
||||
|
377
src/view.rs
Normal file
377
src/view.rs
Normal file
@ -0,0 +1,377 @@
|
||||
use r4::iterate;
|
||||
use symbol_map::indexing::Indexing;
|
||||
|
||||
use crate::base::{EdgeId, RawEdge, RawVertex, VertexId};
|
||||
use crate::mutators;
|
||||
use crate::Graph;
|
||||
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct InvariantLifetime<'id>(pub(crate) PhantomData<*mut &'id ()>);
|
||||
|
||||
/// An editable view of a graph.
|
||||
///
|
||||
/// A `View` wraps around a mutable borrow of a `Graph` and enables taking
|
||||
/// references into the graph and performing mutation operations on
|
||||
/// it. Mutations that invalidate references into the graph consume the view
|
||||
/// entirely. Generally speaking, it is possible to grow the graph (add nodes or
|
||||
/// edges) without invalidating references into it.
|
||||
///
|
||||
/// To create a `View`, use one of the functions defined in this module
|
||||
/// (`of_graph`, `of_node`, or `of_edge`).
|
||||
pub struct View<'a, T: Hash + Eq + Clone, S, A> {
|
||||
graph: &'a mut Graph<T, S, A>,
|
||||
lifetime: InvariantLifetime<'a>,
|
||||
}
|
||||
|
||||
/// Applies a function over a view of `graph` and returns its result.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use search_graph::Graph;
|
||||
/// # use search_graph::view;
|
||||
/// # fn main() {
|
||||
/// let mut graph: Graph<String, String, String> = Graph::new();
|
||||
/// assert_eq!(graph.vertex_count(), 0);
|
||||
/// assert_eq!(graph.edge_count(), 0);
|
||||
/// view::of_graph(&mut graph, |mut v| v.append_node("state".into(), "data".into()));
|
||||
/// assert_eq!(graph.vertex_count(), 1);
|
||||
/// assert_eq!(graph.edge_count(), 0);
|
||||
/// assert_eq!(graph.find_node(&"state".into()).unwrap().get_data(), "data");
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn of_graph<'a, T: Hash + Eq + Clone, S, A, U, F: FnOnce(View<'a, T, S, A>) -> U>(
|
||||
graph: &'a mut Graph<T, S, A>,
|
||||
closure: F,
|
||||
) -> U {
|
||||
closure(View {
|
||||
graph,
|
||||
lifetime: InvariantLifetime(PhantomData),
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies a function over a `MutNode` and a view of its containing graph,
|
||||
/// returning its result.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use search_graph::Graph;
|
||||
/// # use search_graph::view;
|
||||
/// # fn main() {
|
||||
/// let mut graph: Graph<String, String, String> = Graph::new();
|
||||
/// let node = graph.add_node("state".into(), "data".into());
|
||||
/// view::of_node(node, |v, n| {
|
||||
/// assert_eq!(v.node_state(n), "state");
|
||||
/// assert_eq!(v.node_data(n), "data");
|
||||
/// });
|
||||
/// # }
|
||||
pub fn of_node<
|
||||
'a,
|
||||
T: Hash + Eq + Clone,
|
||||
S,
|
||||
A,
|
||||
U,
|
||||
F: FnOnce(View<'a, T, S, A>, NodeRef<'a>) -> U,
|
||||
>(
|
||||
node: mutators::MutNode<'a, T, S, A>,
|
||||
closure: F,
|
||||
) -> U {
|
||||
let lifetime = InvariantLifetime(PhantomData);
|
||||
closure(
|
||||
View {
|
||||
graph: node.graph,
|
||||
lifetime,
|
||||
},
|
||||
NodeRef {
|
||||
id: node.id,
|
||||
_lifetime: lifetime,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Applies a function over a `MutEdge` and a view of its containing graph,
|
||||
/// returning its result.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use search_graph::Graph;
|
||||
/// # use search_graph::view;
|
||||
/// # fn main() {
|
||||
/// let mut graph: Graph<String, String, String> = Graph::new();
|
||||
/// let node = graph.add_node("state".into(), "data".into());
|
||||
/// let edge = view::of_node(node, |mut v, root| {
|
||||
/// let child = v.append_node("child_state".into(), "child_data".into());
|
||||
/// v.into_append_edge(root, child, "edge_data".into())
|
||||
/// });
|
||||
/// view::of_edge(edge, |v, e| assert_eq!(v.edge_data(e), "edge_data"));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn of_edge<
|
||||
'a,
|
||||
T: Hash + Eq + Clone,
|
||||
S,
|
||||
A,
|
||||
U,
|
||||
F: FnOnce(View<'a, T, S, A>, EdgeRef<'a>) -> U,
|
||||
>(
|
||||
edge: mutators::MutEdge<'a, T, S, A>,
|
||||
closure: F,
|
||||
) -> U {
|
||||
let lifetime = InvariantLifetime(PhantomData);
|
||||
closure(
|
||||
View {
|
||||
graph: edge.graph,
|
||||
lifetime,
|
||||
},
|
||||
EdgeRef {
|
||||
id: edge.id,
|
||||
_lifetime: lifetime,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
impl<'a, T: Hash + Eq + Clone, S, A> View<'a, T, S, A> {
|
||||
// Unsafe operations that reference into the underlying graph structure. A
|
||||
// NodeRef or EdgeRef will only have the same invariant lifetime as a View if
|
||||
// it was created for that view, and we only create NodeRef/EdgeRef instances
|
||||
// with valid indices.
|
||||
//
|
||||
// Because vertices/edges cannot be deleted or re-ordered without consuming a
|
||||
// View, it should always be safe to follow reference indices without doing
|
||||
// bounds-checking.
|
||||
fn raw_vertex(&self, node: NodeRef<'a>) -> &RawVertex<S> {
|
||||
unsafe { self.graph.vertices.get_unchecked(node.id.0) }
|
||||
}
|
||||
|
||||
fn raw_vertex_mut(&mut self, node: NodeRef<'a>) -> &mut RawVertex<S> {
|
||||
unsafe { self.graph.vertices.get_unchecked_mut(node.id.0) }
|
||||
}
|
||||
|
||||
fn raw_edge(&self, edge: EdgeRef<'a>) -> &RawEdge<A> {
|
||||
unsafe { self.graph.arcs.get_unchecked(edge.id.0) }
|
||||
}
|
||||
|
||||
fn raw_edge_mut(&mut self, edge: EdgeRef<'a>) -> &mut RawEdge<A> {
|
||||
unsafe { self.graph.arcs.get_unchecked_mut(edge.id.0) }
|
||||
}
|
||||
|
||||
/// Returns a reference to the node for the given game state that is already
|
||||
/// in the graph, or `None` if there is no such node.
|
||||
pub fn find_node(&self, state: &T) -> Option<NodeRef<'a>> {
|
||||
self.graph.find_node(state).map(|n| NodeRef {
|
||||
id: n.id,
|
||||
_lifetime: self.lifetime,
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a node for the given game state with the given data, returning a
|
||||
/// reference to it after it is added. If such a node already exists, no node
|
||||
/// is added to the graph, and a reference to the existing node is returned.
|
||||
pub fn append_node(&mut self, state: T, data: S) -> NodeRef<'a> {
|
||||
NodeRef {
|
||||
id: self.graph.add_node(state, data).id,
|
||||
_lifetime: self.lifetime,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes this view and adds a node as if `append_node` had been
|
||||
/// called. Returns a `MutNode` that points to the node that is created.
|
||||
pub fn into_append_node(self, state: T, data: S) -> mutators::MutNode<'a, T, S, A> {
|
||||
let id = self.graph.add_node(state, data).id;
|
||||
mutators::MutNode {
|
||||
graph: self.graph,
|
||||
id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an edge between the given nodes, returning a reference to it after it
|
||||
/// is added.
|
||||
pub fn append_edge(
|
||||
&mut self,
|
||||
source: NodeRef<'a>,
|
||||
target: NodeRef<'a>,
|
||||
edge_data: A,
|
||||
) -> EdgeRef<'a> {
|
||||
let id = self.graph.add_raw_edge(edge_data, source.id, target.id);
|
||||
EdgeRef {
|
||||
id,
|
||||
_lifetime: self.lifetime,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes this view and adds an edge as if `append_edge` had been
|
||||
/// called. Returns a `MutEdge` that points to the edge that is created.
|
||||
pub fn into_append_edge(
|
||||
self,
|
||||
source: NodeRef<'a>,
|
||||
target: NodeRef<'a>,
|
||||
edge_data: A,
|
||||
) -> mutators::MutEdge<'a, T, S, A> {
|
||||
let id = self.graph.add_raw_edge(edge_data, source.id, target.id);
|
||||
mutators::MutEdge {
|
||||
graph: self.graph,
|
||||
id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the game state that `node` is associated with.
|
||||
pub fn node_state(&self, node: NodeRef<'a>) -> &T {
|
||||
&self
|
||||
.graph
|
||||
.state_ids
|
||||
.get_symbol(&node.id)
|
||||
.as_ref()
|
||||
.map(|x| x.data())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Returns a reference to the data (usually statistics or payout information)
|
||||
/// for `node`.
|
||||
pub fn node_data(&self, node: NodeRef<'a>) -> &S {
|
||||
&self.raw_vertex(node).data
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the data (usually statistics or payout
|
||||
/// information) for `node`.
|
||||
pub fn node_data_mut(&mut self, node: NodeRef<'a>) -> &mut S {
|
||||
&mut self.raw_vertex_mut(node).data
|
||||
}
|
||||
|
||||
/// Returns a reference to the data (usually statistics or payout information)
|
||||
/// for `edge`.
|
||||
pub fn edge_data(&self, edge: EdgeRef<'a>) -> &A {
|
||||
&self.raw_edge(edge).data
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the data (usually statistics or payout
|
||||
/// information) for `edge`.
|
||||
pub fn edge_data_mut(&mut self, edge: EdgeRef<'a>) -> &mut A {
|
||||
&mut self.raw_edge_mut(edge).data
|
||||
}
|
||||
|
||||
/// Returns a reference to the node that `edge` originates from.
|
||||
pub fn edge_source(&self, edge: EdgeRef<'a>) -> NodeRef<'a> {
|
||||
NodeRef {
|
||||
id: self.raw_edge(edge).source,
|
||||
_lifetime: self.lifetime,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the node that `edge` terminates on.
|
||||
pub fn edge_target(&self, edge: EdgeRef<'a>) -> NodeRef<'a> {
|
||||
NodeRef {
|
||||
id: self.raw_edge(edge).target,
|
||||
_lifetime: self.lifetime,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of children (outgoing edges) that `node` has.
|
||||
pub fn child_count(&self, node: NodeRef<'a>) -> usize {
|
||||
self.raw_vertex(node).children.len()
|
||||
}
|
||||
|
||||
/// Returns an iterator over the children (outgoing edges) that `node` has.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use search_graph::Graph;
|
||||
/// # use search_graph::view;
|
||||
/// # fn main() {
|
||||
/// let mut g: Graph<String, String, String> = Graph::new();
|
||||
/// view::of_graph(&mut g, |mut v| {
|
||||
/// let root = v.append_node("root_state".into(), "root_data".into());
|
||||
/// let child1 = v.append_node("child1_state".into(), "child1_data".into());
|
||||
/// let child2 = v.append_node("child2_state".into(), "child2_data".into());
|
||||
/// let child3 = v.append_node("child3_state".into(), "child3_data".into());
|
||||
/// v.append_edge(root, child1, "edge1_data".into());
|
||||
/// v.append_edge(root, child2, "edge2_data".into());
|
||||
/// v.append_edge(root, child3, "edge3_data".into());
|
||||
/// let edge_data: Vec<&String> = v.children(root).map(|e| v.edge_data(e)).collect();
|
||||
/// assert_eq!(edge_data, vec!["edge1_data", "edge2_data", "edge3_data"]);
|
||||
/// let child_data: Vec<&String> =
|
||||
/// v.children(root).map(|e| v.node_data(v.edge_target(e))).collect();
|
||||
/// assert_eq!(child_data, vec!["child1_data", "child2_data", "child3_data"]);
|
||||
/// });
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn children<'s>(&'s self, node: NodeRef<'a>) -> impl Iterator<Item = EdgeRef<'a>> + 's {
|
||||
iterate!(for id in self.raw_vertex(node).children.iter();
|
||||
yield EdgeRef { id: *id, _lifetime: self.lifetime, })
|
||||
}
|
||||
|
||||
/// Returns the number of parents (incoming edges) that `node` has.
|
||||
pub fn parent_count(&self, node: NodeRef<'a>) -> usize {
|
||||
self.raw_vertex(node).parents.len()
|
||||
}
|
||||
|
||||
/// Returns an iterator over the parents (incoming edges) that `node` has.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use search_graph::Graph;
|
||||
/// # use search_graph::view;
|
||||
/// # fn main() {
|
||||
/// let mut g: Graph<String, String, String> = Graph::new();
|
||||
/// view::of_graph(&mut g, |mut v| {
|
||||
/// let child = v.append_node("child_state".into(), "child_data".into());
|
||||
/// let parent1 = v.append_node("parent1_state".into(), "parent1_data".into());
|
||||
/// let parent2 = v.append_node("parent2_state".into(), "parent2_data".into());
|
||||
/// let parent3 = v.append_node("parent3_state".into(), "parent3_data".into());
|
||||
/// v.append_edge(parent1, child, "edge1_data".into());
|
||||
/// v.append_edge(parent2, child, "edge2_data".into());
|
||||
/// v.append_edge(parent3, child, "edge3_data".into());
|
||||
/// let edge_data: Vec<&String> = v.parents(child).map(|e| v.edge_data(e)).collect();
|
||||
/// assert_eq!(edge_data, vec!["edge1_data", "edge2_data", "edge3_data"]);
|
||||
/// let parent_data: Vec<&String> =
|
||||
/// v.parents(child).map(|e| v.node_data(v.edge_source(e))).collect();
|
||||
/// assert_eq!(parent_data, vec!["parent1_data", "parent2_data", "parent3_data"]);
|
||||
/// });
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn parents<'s>(&'s self, node: NodeRef<'a>) -> impl Iterator<Item = EdgeRef<'a>> + 's {
|
||||
iterate!(for id in self.raw_vertex(node).parents.iter();
|
||||
yield EdgeRef { id: *id, _lifetime: self.lifetime, })
|
||||
}
|
||||
|
||||
/// Deletes all graph components that are not reachable by a traversal
|
||||
/// starting from each of `roots`.
|
||||
pub fn retain_reachable_from<I: IntoIterator<Item = NodeRef<'a>>>(&mut self, roots: I) {
|
||||
let root_ids: Vec<VertexId> = roots.into_iter().map(|n| n.id).collect();
|
||||
self.retain_reachable_from_ids(&root_ids);
|
||||
}
|
||||
|
||||
/// As `retain_reachable_from`, but working over raw `VertexId`s.
|
||||
fn retain_reachable_from_ids(&mut self, root_ids: &[VertexId]) {
|
||||
mutators::mark_compact::Collector::retain_reachable(self, root_ids);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Hash + Eq + Clone, S, A> Deref for View<'a, T, S, A> {
|
||||
type Target = Graph<T, S, A>;
|
||||
|
||||
fn deref(&self) -> &Graph<T, S, A> {
|
||||
self.graph
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Hash + Eq + Clone, S, A> DerefMut for View<'a, T, S, A> {
|
||||
fn deref_mut(&mut self) -> &mut Graph<T, S, A> {
|
||||
self.graph
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Hash + Eq + Clone, S, A> From<View<'a, T, S, A>> for &'a mut Graph<T, S, A> {
|
||||
fn from(view: View<'a, T, S, A>) -> &'a mut Graph<T, S, A> {
|
||||
view.graph
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct NodeRef<'a> {
|
||||
pub(crate) id: VertexId,
|
||||
pub(crate) _lifetime: InvariantLifetime<'a>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct EdgeRef<'a> {
|
||||
pub(crate) id: EdgeId,
|
||||
pub(crate) _lifetime: InvariantLifetime<'a>,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user