How can I store a type directly in a struct when all the traits I need are implemented for references to that type?

timthelion

Petgraph implements all its traits for references to it's internal graph type. How can I store and use a Graph rather than an &Graph in a struct?

This works but stores a reference to the graph:

extern crate petgraph;

use crate::petgraph::visit::*;
use petgraph::data::*;
use petgraph::*;

struct StateMachine<G>
where
    G: GraphBase,
{
    state_network: G,
    state: <G as GraphBase>::NodeId,
}

impl<G> StateMachine<G>
where
    G: IntoNodeReferences
        + IntoEdgeReferences
        + IntoEdges
        + Data
        + NodeIndexable
        + GraphProp
        + DataMap
        + GraphBase,
    <G as Data>::NodeWeight: Eq + Copy,
    <G as Data>::EdgeWeight: Eq + Copy,
{
    pub fn next(&mut self, input: <G as Data>::EdgeWeight) -> Option<<G as Data>::NodeWeight> {
        for edge in self.state_network.edges(self.state) {
            if *edge.weight() == input {
                self.state = edge.target();
                return match self.state_network.node_weight(self.state) {
                    Option::Some(weight) => Some(*weight),
                    Option::None => Option::None,
                };
            }
        }
        return Option::None;
    }

    pub fn new(network: G, start: <G as Data>::NodeWeight) -> Option<StateMachine<G>> {
        for nr in network.node_references() {
            if *(network.node_weight(nr.id())).unwrap() == start {
                return Option::Some(StateMachine {
                    state_network: network,
                    state: nr.id(),
                });
            }
        }
        return Option::None;
    }
}

fn main() {
    let mut sn: Graph<&str, u32, petgraph::Directed> = Graph::new();
    let sn_item1 = sn.add_node("a");
    let sn_item2 = sn.add_node("b");
    let sn_item3 = sn.add_node("c");
    let sn_item4 = sn.add_node("d");
    let sn_item5 = sn.add_node("e");
    sn.add_edge(sn_item1, sn_item2, 1);
    sn.add_edge(sn_item1, sn_item3, 2);
    sn.add_edge(sn_item2, sn_item4, 1);
    sn.add_edge(sn_item2, sn_item5, 2);
    sn.add_edge(sn_item5, sn_item1, 2);
    sn.add_edge(sn_item5, sn_item3, 1);
    let mut sm = StateMachine::new(&sn, "a").unwrap();
    println!("{}", sm.next(1).unwrap());
}

Link to rust playground

But storing the Graph directly doesn't work

extern crate petgraph;

use crate::petgraph::visit::*;
use petgraph::data::*;
use petgraph::*;

struct StateMachine<'a, G>
where
    &'a G: GraphBase,
{
    state_network: G,
    state: <&'a G as GraphBase>::NodeId,
}

impl<'a, G> StateMachine<'a, G>
where
    &'a G: IntoNodeReferences
        + IntoEdgeReferences
        + IntoEdges
        + Data
        + NodeIndexable
        + GraphProp
        + DataMap
        + GraphBase,
    <&'a G as Data>::NodeWeight: Eq + Copy,
    <&'a G as Data>::EdgeWeight: Eq + Copy,
{
    pub fn next(&mut self, input: <&'a G as Data>::EdgeWeight) -> Option<<&'a G as Data>::NodeWeight> {
        for edge in (&self.state_network).edges(self.state) {
            if *edge.weight() == input {
                self.state = edge.target();
                return match (&self.state_network).node_weight(self.state) {
                    Option::Some(weight) => Some(*weight),
                    Option::None => Option::None,
                };
            }
        }
        return Option::None;
    }

    pub fn new(network: G, start: <&'a G as Data>::NodeWeight) -> Option<StateMachine<'a, G>> {
        for nr in network.node_references() {
            if *((&network).node_weight(nr.id())).unwrap() == start {
                return Option::Some(StateMachine {
                    state_network: network,
                    state: nr.id(),
                });
            }
        }
        return Option::None;
    }
}

fn main() {
    let mut sn: Graph<&str, u32, petgraph::Directed> = Graph::new();
    let sn_item1 = sn.add_node("a");
    let sn_item2 = sn.add_node("b");
    let sn_item3 = sn.add_node("c");
    let sn_item4 = sn.add_node("d");
    let sn_item5 = sn.add_node("e");
    sn.add_edge(sn_item1, sn_item2, 1);
    sn.add_edge(sn_item1, sn_item3, 2);
    sn.add_edge(sn_item2, sn_item4, 1);
    sn.add_edge(sn_item2, sn_item5, 2);
    sn.add_edge(sn_item5, sn_item1, 2);
    sn.add_edge(sn_item5, sn_item3, 1);
    let mut sm = StateMachine::new(sn, "a").unwrap();
    println!("{}", sm.next(1).unwrap());
}

Link to rust playgound

  Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:29:21
   |
29 |         for edge in (&self.state_network).edges(self.state) {
   |                     ^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 28:5...
  --> src/main.rs:28:5
   |
28 | /     pub fn next(&mut self, input: <&'a G as Data>::EdgeWeight) -> Option<<&'a G as Data>::NodeWeight> {
29 | |         for edge in (&self.state_network).edges(self.state) {
30 | |             if *edge.weight() == input {
31 | |                 self.state = edge.target();
...  |
38 | |         return Option::None;
39 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:29:21
   |
29 |         for edge in (&self.state_network).edges(self.state) {
   |                     ^^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
  --> src/main.rs:15:6
   |
15 | impl<'a, G> StateMachine<'a, G>
   |      ^^
   = note: ...so that the expression is assignable:
           expected <&G as petgraph::visit::GraphBase>::NodeId
              found <&'a G as petgraph::visit::GraphBase>::NodeId

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:32:30
   |
32 |                 return match (&self.state_network).node_weight(self.state) {
   |                              ^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 28:5...
  --> src/main.rs:28:5
   |
28 | /     pub fn next(&mut self, input: <&'a G as Data>::EdgeWeight) -> Option<<&'a G as Data>::NodeWeight> {
29 | |         for edge in (&self.state_network).edges(self.state) {
30 | |             if *edge.weight() == input {
31 | |                 self.state = edge.target();
...  |
38 | |         return Option::None;
39 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:32:30
   |
32 |                 return match (&self.state_network).node_weight(self.state) {
   |                              ^^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
  --> src/main.rs:15:6
   |
15 | impl<'a, G> StateMachine<'a, G>
   |      ^^
   = note: ...so that the expression is assignable:
           expected <&G as petgraph::visit::GraphBase>::NodeId
              found <&'a G as petgraph::visit::GraphBase>::NodeId

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.
CoronA

I am not familiar with petgraph and its concepts now. From my experience storing references in structs almost always ends with complete rewrites so my approach would have been something like this:

struct StateMachine<G, E, N>
where
  G: GraphBase<EdgeId = E, NodeId = N>,
  E: Copy + PartialEq,
  N: Copy + PartialEq,
{
  state_network: G,
  state: N,
}

impl<G, E, N, EW, NW> StateMachine<G, E, N>
where
  G: Data<NodeWeight = NW, EdgeWeight = EW>
    + NodeIndexable
    + GraphProp
    + DataMap
    + GraphBase<EdgeId = E, NodeId = N>,
  E: Copy + PartialEq,
  N: Copy + PartialEq,
  for<'a> &'a G: IntoNodeReferences
    + IntoEdgeReferences
    + IntoEdges
    + Data<NodeWeight = NW, EdgeWeight = EW>
    + GraphBase<EdgeId = E, NodeId = N>,
  EW: Eq + Copy,
  NW: Eq + Copy,
{
  pub fn next<'a, 'b: 'a>(&'a mut self, input: EW) -> Option<NW> {
    for edge in (&self.state_network).edges(self.state) {
      if *edge.weight() == input {
        self.state = edge.target();
        return match self.state_network.node_weight(self.state) {
          Option::Some(weight) => Some(*weight),
          Option::None => Option::None,
        };
      }
    }
    return Option::None;
  }

  pub fn new(
    network: G,
    start: NW,
  ) -> Option<StateMachine<G, <G as GraphBase>::EdgeId, <G as GraphBase>::NodeId>> {
    let mut found = Option::None;

    for nr in network.node_references() {
      if *(network.node_weight(nr.id())).unwrap() == start {
        found = Option::Some(nr.id());
      }
    }
    found.map(|id| StateMachine {
      state_network: network,
      state: id,
    })
  }
}

EdgeId and NodeId get generic parameters (E,N)since these are reused in the implementation of StateMachine, NodeWeight and EdgeWeight also get generic (NW, EW) but only to join the associated types of &Graph and Graph.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How can I list all implemented traits for a given type during compilation in a macro?

How can I implement trait B for all types that implement trait A if both traits are implemented for references?

Is it possible for traits to impose restrictions for references to the type it is implemented on?

How can I type parameterize a struct that doesn't use that type directly?

How can I use C++ concepts with type_traits?

How can I use Scala reflection to find the self type traits?

How can I tell rust two traits have the same type?

Can I overload functions with type-traits?

How can I store the arguments of a variadic type?

How can I store a type in an array?

How can I restrict an Interface to be implemented by only a generic type

How can i avoid circular references in type aliases

How can I get the type of a function argument using type traits in C++?

How can I create a value type that can be implemented similar to a Native type

Can I get a Span<byte> that references a struct member field of non-byte type?

How can I implement a JPQL query retrieving all the user having a specific type (implemented using a MANY TO MANY relation)?

How can I remove exception "Predefined type 'ValueTuple`2' must be a struct" when debugging?

How can I type all unknown keys as a separate type?

How can I initialize a type that is a pointer to a struct in Go?

How can I consume data type of Rc<RefCell<T>> in struct?

How can I aggregate init a struct that inherits from a virtual type?

How can I define a struct field in my interface as a type constraint?

How can I assign a Struct Type value using a map?

How can I know if a parameter that has the type interface is actually a struct?

How can I have an unused type parameter in a struct?

why do python need unicode type since I can declare a variable directly with any unicode character?

How can I identify when a Kotlin type will be mapped to a Java type?

how can I add more type when type of parameter existed

How can I use type-traits to make this array-to-pointer conversion unambiguous?