///|
/// Each step names the owning element of a nested graph, by its ordinal in that graph.
pub(all) enum GraphStep {
NodeGraph(Int32)
EdgeGraph(Int32)
HyperedgeGraph(Int32)
} derive(Eq, @debug.Debug)
///|
pub extend GraphStep with Eq::{equal, not_equal}
///|
pub extend GraphStep with @debug.Debug::{to_repr}
///|
pub(all) struct GraphAddress {
root : Int32
steps : Array[GraphStep]
} derive(Eq, @debug.Debug)
///|
pub extend GraphAddress with Eq::{equal, not_equal}
///|
pub extend GraphAddress with @debug.Debug::{to_repr}
///|
pub fn GraphAddress::root(index : Int32) -> GraphAddress {
{ root: index, steps: [], }
}
///|
pub fn GraphAddress::child(
self : GraphAddress,
step : GraphStep,
) -> GraphAddress {
let steps = self.steps.copy()
steps.push(step)
{ root: self.root, steps, }
}
///|
fn copy_address(address : GraphAddress) -> GraphAddress {
{ ..address, steps: address.steps.copy(), }
}
///|
fn bounded_index(
index : Int32,
size : Int32,
path : String,
) -> Unit raise GraphError {
require(index >= 0 && index < size, path, "index out of range")
}
///|
fn graph_at(doc : Document, address : GraphAddress) -> Graph raise GraphError {
bounded_index(address.root, doc.graphs.length(), "graph.root")
let mut graph = doc.graphs[address.root]
for step in address.steps {
let nested = match step {
NodeGraph(index) => {
bounded_index(index, graph.nodes.length(), "graph.node")
graph.nodes[index].graph
}
EdgeGraph(index) => {
bounded_index(index, graph.edges.length(), "graph.edge")
graph.edges[index].graph
}
HyperedgeGraph(index) => {
bounded_index(index, graph.hyperedges.length(), "graph.hyperedge")
graph.hyperedges[index].graph
}
}
graph = match nested {
Some(value) => value
None =>
raise InvalidGraph(
path="graph.address",
reason="owning element has no nested graph",
)
}
}
graph
}
///|
/// Get a detached graph using a structural address, including graphs without IDs.
pub fn Document::graph_at(
self : Document,
address : GraphAddress,
) -> Graph raise GraphError {
clone_graph(graph_at(self, address))
}