I'm writing very basic AI system in Rust. It's main components are:
Actions, which can be implemented by library user, for specific use,- Generic
Context, which is passed to all actions, and only needs to live during the action execution, ActionsContainer, which "globally" stores all possible actions,System, which chooses the correct action and runs it. There are many systems, one for each agent. However, they share the same set of behaviours, so they all reference a commonActionsContainer.
Here is a minimum example which illustrates my problem.
// Generic system
trait Context {}
trait Action<C: Context> {
fn run(&self, context: &mut C);
}
struct ActionsContainer<C: Context> {
actions: Vec<Box<Action<C>>>,
}
struct System<'a, C: Context> {
actions: &'a ActionsContainer<C>,
}
impl<'a, C: Context> System<'a, C> {
fn run(&self, c: &mut C) {
self.actions.actions[0].run(c);
}
}
// Implementation
struct ContextImpl<'a> {
x: &'a i32,
y: i32,
}
impl<'a> Context for ContextImpl<'a> {}
struct ActionImpl {}
impl<'a> Action<ContextImpl<'a>> for ActionImpl {
fn run(&self, c: &mut ContextImpl) {
println!("Action!");
c.y = c.x;
}
}
// usage
fn main() {
let container = ActionsContainer {
actions: vec![Box::new(ActionImpl {})],
};
{
let system = System {
actions: &container,
};
{
let x = 8;
let mut context = ContextImpl { x: &x, y: 0 };
system.run(&context);
assert_eq!(context.y, context.x)
}
}
}
The compiler complains:
error[E0309]: the parameter type `C` may not live long enough
--> src/main.rs:14:5
|
13 | struct System<'a, C: Context> {
| -- help: consider adding an explicit lifetime bound `C: 'a`...
14 | actions: &'a ActionsContainer<C>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...so that the reference type `&'a ActionsContainer<C>` does not outlive the data it points at
--> src/main.rs:14:5
|
14 | actions: &'a ActionsContainer<C>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
However, C is not stored in Action. It only needs to live while run is executing. On the other hand, the Action does need to live as long as whole System. Is there any way to annotate this?
I suspect, it has something to do with Higher-Rank Trait Bounds, but I don't see how to use them here.
I've also tried to get rid of Action as a trait object and just use plain function references:
type Action<C> = fn(&mut C);
struct ActionsContainer<C: Context> {
actions: Vec<&'static Action<C>>,
}
But the compiler error was pretty much the same.