I'm not sure this is really related specifically to GATs, but I need GATs to represent what I am trying to do.
For context, I am writing a game networking library which takes a world, say a hecs::World, and can add/remove objects from the world, inspect objects, and mutate objects. But to inspect/mutate objects it requires borrowing a "view", which allows one to inspect/mutate exactly one object at a time (and as long as the view is held, no objects can be added or removed).
I can do this naturally by directly borrowing a hecs::World, but my intention is to make this more general so as to not be tied down to hecs.
Below is a very pared down attempt at this using GATs.
#![feature(generic_associated_types)]
struct Object {}
trait Viewer<'a> {
// the same function without the 'b doesn't work either and as I understand
// should be no different. I.e., borrow checker already looks for a 'b
// that is no longer than 'a
fn get_object<'b>(&'a self, world_object_id: u32) -> &'b Object where 'a:'b;
}
trait World {
type WorldViewer<'a>: Viewer<'a> where Self: 'a;
fn get_view(&self) -> Self::WorldViewer<'_>;
// This doesn't work either:
// fn get_view<'a>(&'a self) -> Self::WorldViewer<'a>;
}
fn _test(world: &impl World) {
let view = world.get_view();
// add an extra scope to help borrow checker as much as possible
{
let _o = view.get_object(1);
}
}
fn main() {
}
Compiling playground v0.0.1 (/playground)
error[E0597]: `view` does not live long enough
--> src/main.rs:26:18
|
26 | let _o = view.get_object(1);
| ^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
27 | }
28 | }
| -
| |
| `view` dropped here while still borrowed
| borrow might be used here, when `view` is dropped and runs the destructor for type `<impl World as World>::WorldViewer<'_>`
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error
I understand that the impl is forcing a drop check, and that is why I get this specific error. But if I create a struct that implements the World trait and pass a reference to that instead I still get an error if I try to call get_object a second time. So somehow the get_object call is permanently borrowing the lifetime of view and I don't get why.