How to wrap up functions using NodeIndex in petgraph - rust

Newbie question: I want to use the petgraph rust crate. The graph should be a part of the struct MyGraph. For this, I need to wrap some functions to make them acessible from outside:
use petgraph::graph::DiGraph;
use petgraph::adj::NodeIndex;
#[derive(Default)]
struct MyNode {}
#[derive(Default)]
struct MyGraph {
g: DiGraph<MyNode,()>
}
impl MyGraph {
pub fn add_node(&mut self, node: MyNode) -> NodeIndex {
self.g.add_node(node) // does not compile: return value is u32 != NodeIndex
}
pub fn update_edge(&mut self, a: NodeIndex, b: NodeIndex) {
self.g.update_edge(a, b, ()); // does not compile: a: NodeIndex expected, got u32
}
}
fn main() {
let mut my_graph=MyGraph::default();
let node1=my_graph.add_node(MyNode::default());
let node2=my_graph.add_node(MyNode::default());
my_graph.update_edge(node1,node2);
}
The rust compiler however complains the an u32 is returned by the self.g.add_node() function, which is not the case if you call the function directly (and it's documented to return a NodeIndex). The smae problem applies to the self.g.update_edge() function. What would be the correct parameter type to use here???
A return type NodeIndex did not work as well. The (partial) compile error message:
...
error[E0308]: arguments to this function are incorrect
--> src\main.rs:17:16
|
17 | self.g.update_edge(a, b, ());
| ^^^^^^^^^^^
|
note: expected struct `NodeIndex`, found `u32`
--> src\main.rs:17:28
|
17 | self.g.update_edge(a, b, ());
| ^
= note: expected struct `NodeIndex`
found type `u32`
...
What I am doing wrong here?

You're importing petgraph::adj::NodeIndex, which is an alias for u32, but what you need to import is petgraph::graph::NodeIndex, which is a different struct.

Related

How to call Iter::chain and what will be the return type?

I'm trying to create an iterator that will add one element to the start of a vector
struct World {
player: Object,
npcs: Vec<Object>,
}
impl World {
pub fn all_objects(&mut self) -> ???
}
I understand I need to use the chain function for this but I'm not sure how, or what will the return type be
Maybe someone can explain to me how to use it?
The exact types of iterators can be complex. A fast way to determine them is to try to return the wrong type on purpose, and see what the compiler says:
struct Object;
struct World {
player: Object,
npcs: Vec<Object>,
}
impl World {
pub fn all_objects(&mut self) -> () {
std::iter::once(&self.player).chain(self.npcs.iter())
}
}
(Permalink to the playground)
This gives:
error[E0308]: mismatched types
--> src/lib.rs:10:9
|
9 | pub fn all_objects(&mut self) -> () {
| -- expected `()` because of return type
10 | std::iter::once(&self.player).chain(self.npcs.iter())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
| |
| expected `()`, found struct `std::iter::Chain`
|
= note: expected unit type `()`
found struct `std::iter::Chain<std::iter::Once<&Object>, std::slice::Iter<'_, Object>>`
and indeed if you replace that, it will compile:
struct Object;
struct World {
player: Object,
npcs: Vec<Object>,
}
impl World {
pub fn all_objects(
&mut self,
) -> std::iter::Chain<std::iter::Once<&Object>, std::slice::Iter<'_, Object>> {
std::iter::once(&self.player).chain(self.npcs.iter())
}
}
But the exact type usually doesn't matter with iterators, so you can simply specify that your function returns some kind of iterator:
struct Object;
struct World {
player: Object,
npcs: Vec<Object>,
}
impl World {
pub fn all_objects(&mut self) -> impl Iterator<Item = &Object> {
std::iter::once(&self.player).chain(self.npcs.iter())
}
}
(Permalink to the playground)
This is also more flexible, as it will let you change the implementation without affecting the users of the function.

How to solve "expected struct, found type parameter" on assignment?

Just started working with Rust a couple of days ago. I'm porting some C++ code right now, and this question seems to be the reverse of the common "expected struct, got type" sort. This code involves two classes, a container class A and a client class B.
use std::vec::Vec;
struct A<T:FooTrait> {
children: Vec<*mut T>
}
impl <T:FooTrait> A<T> {
fn insert(&mut self, val: &mut T) -> Handle<T> {
self.children.push(val);
return Handle{owner: self};
}
}
struct B {
handle: Handle<B>
}
trait FooTrait {
fn set_handle<T:FooTrait>(&mut self, h: Handle<T>);
}
impl FooTrait for B {
fn set_handle<B:FooTrait>(&mut self, h: Handle<B>) {
self.handle = h; // <-- Here is the problem
}
}
struct Handle<T:FooTrait> {
owner: *mut A<T>
}
impl <T:FooTrait> Default for Handle<T> {
fn default()->Handle<T> {
Handle {
owner: std::ptr::null_mut()
}
}
}
fn main() {
let mut foo = A::<B> { children: Default::default() };
let mut b = B{handle: Default::default()};
b.handle = foo.insert(&mut b);
}
Getting the error:
error[E0308]: mismatched types
--> src/main.rs:23:23
|
22 | fn set_handle<B:FooTrait>(&mut self, h: Handle<B>) {
| - this type parameter
23 | self.handle = h;
| ^ expected struct `B`, found type parameter `B`
|
= note: expected struct `Handle<B>` (struct `B`)
found struct `Handle<B>` (type parameter `B`)
Simplified version (playground):
use std::marker::PhantomData;
struct B {
handle: PhantomData<B>,
}
trait FooTrait {
fn set_handle<T: FooTrait>(&mut self, h: PhantomData<T>);
}
impl FooTrait for B {
fn set_handle<BType: FooTrait>(&mut self, h: PhantomData<BType>) {
self.handle = h;
}
}
Note that I've changed the name of the type parameter in set_handle. Now the error is more clear:
error[E0308]: mismatched types
--> src/lib.rs:13:23
|
12 | fn set_handle<BType: FooTrait>(&mut self, h: PhantomData<BType>) {
| ----- this type parameter
13 | self.handle = h;
| ^ expected struct `B`, found type parameter `BType`
|
= note: expected struct `std::marker::PhantomData<B>`
found struct `std::marker::PhantomData<BType>`
In your case, the error is essentially the same, since the generic parameter is a new type, which shadowed the global struct B.
Now, what to do? It depends on what do you want to get.
If the struct B definition is correct and set_handle need to handle only Bs, just remove the generic parameter from set_handle (playground):
trait FooTrait {
fn set_handle(&mut self, h: PhantomData<B>);
}
impl FooTrait for B {
fn set_handle(&mut self, h: PhantomData<B>) {
self.handle = h;
}
}
If the struct B definition is correct, but set_handle must be able to use different handler types depending on Self, use an associated type (playground):
trait FooTrait {
type T: FooTrait;
fn set_handle(&mut self, h: PhantomData<Self::T>);
}
impl FooTrait for B {
type T = B;
fn set_handle(&mut self, h: PhantomData<B>) {
self.handle = h;
}
}
Now the implementation block will choose what kind of argument (handler, in your case) it will get.
If the set_handle definition is correct, i.e. the caller can choose the type of handler, then struct B must be generic, too. However, in this case you essentially can't use the trait-based approach, since the trait has to be generic too, and you will not be able to simply use it in any generic bound without providing parameters (which has to be bound too, ad infinitum).
There are two different B here. The original B you defined in struct B, and the second <B:FooTrait> type parameter. The second is shadowing the first. Here is how the compiler sees it:
impl FooTrait for B {
fn set_handle<AnyFoo:FooTrait>(&mut self, h: Handle<AnyFoo>) {
self.handle = h; // <-- Here is the problem
}
}
The way you've defined things, FooTrait::set_handle is supposed to work with any type that implements FooTrait, but the handle field of B can only store a Handle<B>. You need to rethink what you want FooTrait to do and how B satisfies it.

Function overloading trick - compiler cannot choose which function to call

Rust has no function overloading: you cannot define multiple functions with the same name but with different arguments.
However, I discovered the following trick which makes it look like there is function overloading. Notice how in main() I can call example.apply(...) with different types:
struct Example;
trait Apply<T, R> {
fn apply(&self, value: T) -> R;
}
impl Apply<i32, i32> for Example {
fn apply(&self, value: i32) -> i32 {
value * 2
}
}
impl Apply<&str, String> for Example {
fn apply(&self, value: &str) -> String {
format!("Hello, {}", value)
}
}
fn main() {
let example = Example;
// Looks like function overloading!
let one = example.apply(12);
let two = example.apply("World");
println!("{}", one);
println!("{}", two);
}
Now I would like to make two different versions of the Apply trait: one for values which are Copy and one for values which are not Copy:
struct Example;
struct NotCopy(i32);
// For types which are Copy
trait ApplyCopy<T: Copy, R> {
fn apply(&self, value: T) -> R;
}
// For types which are not Copy
trait ApplyRef<T, R> {
fn apply(&self, value: &T) -> R;
}
impl ApplyCopy<i32, i32> for Example {
fn apply(&self, value: i32) -> i32 {
value * 2
}
}
impl ApplyRef<NotCopy, String> for Example {
fn apply(&self, value: &NotCopy) -> String {
format!("NotCopy({})", value.0)
}
}
However, when I try to use this I get errors:
fn main() {
let example = Example;
let one = example.apply(12); // Error: multiple `apply` found
let two = example.apply(&NotCopy(34)); // Error: multiple `apply` found
println!("{}", one);
println!("{}", two);
}
One of the error messages:
error[E0034]: multiple applicable items in scope
--> src/main.rs:30:23
|
30 | let one = example.apply(12); // Error: multiple `apply` found
| ^^^^^ multiple `apply` found
|
note: candidate #1 is defined in an impl of the trait `ApplyCopy` for the type `Example`
--> src/main.rs:16:5
|
16 | fn apply(&self, value: i32) -> i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `ApplyRef` for the type `Example`
--> src/main.rs:22:5
|
22 | fn apply(&self, value: &NotCopy) -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #1
|
30 | let one = ApplyCopy::apply(&example, 12); // Error: multiple `apply` found
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #2
|
30 | let one = ApplyRef::apply(&example, 12); // Error: multiple `apply` found
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The compiler complains that it does not know which apply function to call. I expected it to be able to make a choice: an i32 is not a reference and is Copy, so the apply of trait ApplyCopy is the only one that can be called, and &NotCopy(34) is a reference and since NotCopy is not Copy, only the apply of ApplyRef can be called.
Is this a limitation of the Rust compiler or am I missing something?
Is this a limitation of the Rust compiler or am I missing something?
While there is compiler magic & special casing around them, at a fundamental level a reference is still a proper type, so any T could be an &Q under the covers, and reference types can implement traits.
While NotCopy is not Copy, &NotCopy is Copy. So &NotCopy matches both cases.

How to disambiguate generic trait method call?

I have the following code:
struct X { i: i32 }
trait MyTrait<T> {
fn hello(&self);
}
impl MyTrait<i32> for X {
fn hello(&self) { println!("I'm an i32") }
}
impl MyTrait<String> for X {
fn hello(&self) { println!("I'm a String") }
}
fn main() {
let f = X { i: 0 };
f.hello();
}
which obviously does not compile as the compiler cannot disambiguate to which trait the f.hello() belongs. So I'm getting the error
error[E0282]: type annotations needed
--> src\main.rs:17:7
|
17 | f.hello();
| ^^^^^ cannot infer type for type parameter `T` declared on the trait `MyTrait`
Is there any way to annotate the type of hello so I can tell the compiler to e.g. invoke MyTrait<String>::hello on f?
After some digging in I bumped into the "Fully Qualified Syntax for Disambiguation: Calling Methods with the Same Name" from the Rust Book. The situation can be adapted to mine, and one can use f as a receiver for the corresponding trait method
<X as MyTrait<String>>::hello(&f);
This compiles and works as intended.
Or even
<MyTrait<String>>::hello(&f);
works.
You can use fully qualified function call syntax:
fn main() {
let f: X;
// shorthand form
MyTrait::<String>::hello(&f);
// expanded form, with deduced type
<_ as MyTrait<String>>::hello(&f);
// expanded form, with explicit type
<X as MyTrait<String>>::hello(&f);
}
Run in Playground

"expected type parameter, found struct" when implementing trait

I am trying to create a trait for a directed graph structure and provide one very basic implementatio, but am running into compiler errors:
pub trait DiGraph<'a> {
type N;
fn nodes<T>(&'a self) -> T where T: Iterator<Item=&'a Self::N>;
fn pre<T>(&'a self, node: Self::N) -> T where T: Iterator<Item=&'a Self::N>;
fn succ<T>(&'a self, node: Self::N) -> T where T: Iterator<Item=&'a Self::N>;
}
struct SimpleNode {
pre: Vec<usize>,
succ: Vec<usize>,
}
pub struct SimpleDiGraph {
pub nodes: Vec<SimpleNode>
}
impl<'a> DiGraph<'a> for SimpleDiGraph {
type N = usize;
fn nodes<T=std::ops::Range<usize>>(&'a self) -> T {
return std::ops::Range { start: 0, end: self.nodes.len() };
}
fn pre<T=std::slice::Iter<'a,usize>>(&'a self, node: usize) -> T {
return self.nodes[node].pre.iter();
}
fn succ<T=std::slice::Iter<'a,usize>>(&'a self, node: usize) -> T {
return self.nodes[node].succ.iter();
}
}
The error messages are:
error[E0308]: mismatched types
--> digraph.rs:21:16
|
21 | return std::ops::Range { start: 0, end: self.nodes.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::ops::Range`
|
= note: expected type `T`
= note: found type `std::ops::Range<usize>`
error[E0308]: mismatched types
--> digraph.rs:24:16
|
24 | return self.nodes[node].pre.iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter`
|
= note: expected type `T`
= note: found type `std::slice::Iter<'_, usize>`
error[E0308]: mismatched types
--> digraph.rs:27:16
|
27 | return self.nodes[node].succ.iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter`
|
= note: expected type `T`
= note: found type `std::slice::Iter<'_, usize>`
The error message is somewhat confusing to me - why would a type parameter be expected as return value? Is this simply a type mismatch (e.g. due to lifetimes) with a misleading error message?
<T=std::ops::Range<usize>> doesn't force T to be std::ops::Range<usize>, it just causes it to default to that if it doesn't know what else to use.
If you only ever want to return a Range<usize>, then use Range<usize> as the return type; there's no reason to have a generic parameter at all. What your code is effectively saying now is something like this:
"You can pick any return type you want! If you don't care, I'll return a range<usize>."
"I'd like you to return a String, please."
"TOUGH you're getting a range<usize>!"
"... but you said..."
"I lied! MUAHAHAHAHAHA!"
If you actually want the caller to choose the return type, then you need to be prepared to return any T... which is almost impossible, since it could be anything from () to String to an OpenGL render context.
In that case, what you actually want to do is constrain T to some trait that requires types implement some sort of construction function. Default is an example of one.
Edit: Just to doubly clarify: you don't get to pick the types used in generic parameters, your caller does.
I didn't notice until just now that you're using different definitions in the trait and the implementation (don't do that). I assume that what you're really trying to do is say "this method returns something that's usable as an Iterator, but each impl can pick a different type." You cannot do this with generics.
What you want is an associated type on the trait, like so:
pub trait DiGraph<'a> {
type Nodes;
fn nodes(&'a self) -> Self::Nodes;
}
pub struct SimpleNode {
pre: Vec<usize>,
succ: Vec<usize>,
}
pub struct SimpleDiGraph {
pub nodes: Vec<SimpleNode>
}
impl<'a> DiGraph<'a> for SimpleDiGraph {
type Nodes = std::ops::Range<usize>;
fn nodes(&'a self) -> Self::Nodes {
return std::ops::Range { start: 0, end: self.nodes.len() };
}
}

Resources