Implement graph-like datastructure in Rust

折月煮酒 提交于 2019-11-26 04:53:54

问题


I have a data structure which can be represented as a unidirectional graph between some structs linked with link objects because links contain metadata.

It looks something like this:

struct StateMachine {
    resources: Vec<Resource>,
    links: Vec<Link>,
}
struct Resource {
    kind: ResourceType,
      // ...
}

enum LinkTarget {
    ResourceList(Vec<&Resource>),
    LabelSelector(HashMap<String, String>),
}

struct Link {
    from: LinkTarget,
    to: LinkTarget,
    metadata: SomeMetadataStruct,
}

The whole structure needs to be mutable because I need to be able to add and remove links and resources at runtime. Because of this, I cannot use the normal lifetime model and bind the resources to the parent struct\'s lifetime.

I understand that I need to \"choose my own guarantee\" by picking the appropriate type, but I\'m not sure what\'s the best way to solve this problem.


回答1:


Actually, for a graph like structure, the simplest solution is to use an arena such as TypedArena.

The lifetime of the nodes will then be only dependent on the lifetime of the instance of the typed arena they were created from, which will greatly simplify resource management.

Warning: avoid a scenario where you dynamically add/remove nodes to the graph, as the nodes will NOT be removed from the arena until said arena is dropped, so the size of the arena would grow, unbounded.


If you are in a situation where you will add/remove nodes at runtime, another solution is to:

  • have a collection of Resources
  • have the edges only indirectly refer to the Resources (not owners, and not borrowers either)

Two examples:

  • HashMap<ResourceId, (Resource, Vec<ResourceId>)>
  • type R = RefCell<Resource>, Vec<Rc<R>> and Vec<(Weak<R>, Vec<Weak<R>>)>

in either case, you are responsible for cleaning up the edges when removing a resource, and forgetting may lead to a memory leak and panics (when dereferencing) but is otherwise safe.

There are, probably, infinite variations on the above.




回答2:


Modeling graph-like structures in Rust is not a simple problem. Here there are two valuable discussions from Nick Cameron and Niko Matsakis (two main Rust developers at Mozilla.)

Graphs and arena allocation

Modeling Graphs in Rust Using Vector Indices




回答3:


The simplest solution for a graph-like structure is to use a library which models graphs. petgraph is a good choice:

extern crate petgraph;

use std::rc::Rc;
use std::collections::HashMap;

use petgraph::Graph;

struct Resource;

enum LinkTarget {
    ResourceList(Vec<Rc<Resource>>),
    LabelSelector(HashMap<String, String>),
}

struct SomeMetadataStruct;

fn main() {
    let mut graph = Graph::new();

    let n1 = graph.add_node(LinkTarget::LabelSelector(Default::default()));
    let n2 = graph.add_node(LinkTarget::LabelSelector(Default::default()));

    let l2 = graph.add_edge(n1, n2, SomeMetadataStruct);
}

The guarantees that you have to choose here center around the member of ResourceList. I assume that you wish to have single-threaded shared immutable Resources.

  • if you need to share them across threads, use a Vec<Arc<Resource>>
  • if they aren't shared just own them — Vec<Resource>
  • if they need to be mutable, use a Vec<Rc<RefCell<Resource>>> (Or a Mutex if also multithreaded)


来源:https://stackoverflow.com/questions/34747464/implement-graph-like-datastructure-in-rust

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!